Форум РадиоКот https://radiokot.ru/forum/ |
|
ATmega8, динамическая индикация, switch case и десятичная то https://radiokot.ru/forum/viewtopic.php?f=57&t=194994 |
Страница 1 из 5 |
Автор: | Denis-1307 [ Сб сен 28, 2024 16:49:42 ] |
Заголовок сообщения: | ATmega8, динамическая индикация, switch case и десятичная то |
Доброго всем времени суток. Начал недавно изучать программирование AVR на Си. Поднакопил немного знаний и решил сделать свое первое устройство, нагрузку для разряда АКБ. Набросал в протеусе вот такую схемку [img][url=https://img.radiokot.ru/files/158040/medium/3kcp23hfco.jpg][/img] Написал в AtmelStudio вот такой код СпойлерКод: #define F_CPU 8000000UL //частота МК #include <avr/io.h> #include <util/delay.h> //библиотека задержек #include <avr/interrupt.h> //библиотека прерываний //---------- динамической индикации------------------------------ unsigned char n = 0; //переменная количества вхождений в прерывание unsigned char r1_1000 = 0; //переменная значения разряда тысяч unsigned char r2_100 = 0; //переменная значения разряда сотен unsigned char r3_10 = 0; //переменная значения разряда десятков unsigned char r4_1 = 0; //переменная значения разряда единиц //---------- //---------- времени--------------------------------------------- unsigned char sec = 0; //переменная количества секунд unsigned char min = 0; //переменная количества минут unsigned char hour = 0; //переменная количества часов //---------- //---------- кнопок (внешние прерывания)---------- unsigned char button_1 = 0; //переменная количества секунд unsigned char button_2 = 0; //переменная количества минут //---------- unsigned int temp = 0; //переменная хранения значения температуры float volt = 0; //переменная хранения значения напряжения АКБ unsigned char n_ADC = 0; //переменная количества преобразований АЦП //---------- индикация и отображение информации---------------- void LED_DISP_pin_setup(void) //функция настройки пинов LED индикатора { //настройка сегментов A, B, Dp, C, G DDRB |= (1<<4) | (1<<3) | (1<<2) | (1<<1) | (1<<0); //режим работы - выход PORTB &= ~((1<<4) | (1<<3) | (1<<2) | (1<<1) | (1<<0)); //низкий потенциал на пинах //настройка сегментов E, D, F DDRD |= (1<<7) | (1<<6) | (1<<5); //режим работы - выход PORTD &= ~((1<<7) | (1<<6) | (1<<5)); //низкий потенциал на пинах //настройка разрядов 1-4 DDRC |= (1<<3) | (1<<2) | (1<<1) | (1<<0); //режим работы - выход PORTC |= (1<<3) | (1<<2) | (1<<1) | (1<<0); //высокий потенциал на пинах } void Timer0_setup(void) //функция настройки нулевого таймер-счетчика { //включение таймер-счетчика с делителем на 64 TCCR0 |= (1<<CS01) | (1<<CS00); TCCR0 &= ~(1<<CS02); //настройка прерывания по переполнению счетого регистра TIMSK |= (1<<TOIE0); //обнуление счетного регистра TCNT0 = 0; } void show_volt(unsigned int znach_volt) { r1_1000 = znach_volt / 1000; //определение значения десятков вольт r2_100 = znach_volt % 1000 / 100; //определение значения единиц вольт r3_10 = znach_volt % 100 / 10; //определение значения десятоых долей вольта r4_1 = 12; //знак напряжения } void show_temp(unsigned int znach_temp) { r1_1000 = znach_temp / 10; // r2_100 = znach_temp % 10; // r3_10 = 10; r4_1 = 11; } void show_min_sec(unsigned int znach_min, unsigned char znach_sec) { r1_1000 = znach_min / 10; //определение значения десятков минут r2_100 = znach_min % 10; //определение значения единиц минут r3_10 = znach_sec / 10; //определение значения десятков секунд r4_1 = znach_sec % 10; //определение значения единиц секунд } void show_hour_min(unsigned int znach_hour, unsigned char znach_min) { r1_1000 = znach_hour / 10; //определение значения десятков часов r2_100 = znach_hour % 10; //определение значения единиц часов r3_10 = znach_min / 10; //определение значения десятков минут r4_1 = znach_min % 10; //определение значения единиц минут } void digits(unsigned char n) //функция отображения цифр { //выключаем сегменты PORTB &= ~((1<<4) | (1<<3) | (1<<2) | (1<<1) | (1<<0)); //низкий потенциал на пинах PORTD &= ~((1<<7) | (1<<6) | (1<<5)); //низкий потенциал на пинах switch(n) { case 0: PORTB |= (1<<3) | (1<<1) | (1<<0); PORTD |= (1<<7) | (1<<6) | (1<<5); break; case 1: PORTB |= (1<<3) | (1<<1); break; case 2: PORTB |= (1<<4) | (1<<1) | (1<<0); PORTD |= (1<<6) | (1<<5); break; case 3: PORTB |= (1<<4) | (1<<3) | (1<<1) | (1<<0); PORTD |= (1<<6); break; case 4: PORTB |= (1<<4) | (1<<3) | (1<<1); PORTD |= (1<<7); break; case 5: PORTB |= (1<<4) | (1<<3) | (1<<0); PORTD |= (1<<7) | (1<<6); break; case 6: PORTB |= (1<<4) | (1<<3) | (1<<0); PORTD |= (1<<7) | (1<<6) | (1<<5); break; case 7: PORTB |= (1<<3) | (1<<1) | (1<<0); break; case 8: PORTB |= (1<<4) | (1<<3) | (1<<1) | (1<<0); PORTD |= (1<<7) | (1<<6) | (1<<5); break; case 9: PORTB |= (1<<4) | (1<<3) | (1<<1) | (1<<0); PORTD |= (1<<7) | (1<<6); break; case 10: PORTB |= (1<<4) | (1<<1) | (1<<0); //знак градуса PORTD |= (1<<7); break; case 11: PORTB |= (1<<0); //знак цельсия PORTD |= (1<<7) | (1<<6) | (1<<5); break; case 12: PORTB |= (1<<3) | (1<<1); //знак напряжения PORTD |= (1<<7) | (1<<6) | (1<<5); break; } } ISR(TIMER0_OVF_vect) //макрос обработки прерывания нулевого таймер-счтечика { if(++n > 4) n = 1; if (n == 1) //отображение в первом разряде { PORTC |= (1<<3) | (1<<2) | (1<<1); PORTC &= ~(1<<0); digits(r1_1000); } else if (n == 2) //отображение во втором разряде { PORTC |= (1<<3) | (1<<2) | (1<<0); PORTC &= ~(1<<1); digits(r2_100); } else if (n == 3) //отображение в третьем разряде { PORTC |= (1<<3) | (1<<1) | (1<<0); PORTC &= ~(1<<2); digits(r3_10); } else if (n == 4) //отображение в четвертом разряде { PORTC |= (1<<2) | (1<<1) | (1<<0); PORTC &= ~(1<<3); digits(r4_1); } } //---------- //---------- одной секунды-------------------------------------------------- void Timer1_setup(void) { //включение таймер-счетчика с делителем на 256 TCCR1B |= (1<<CS12); TCCR1B &= ~((1<<CS11) | (1<<CS10)); //разрешаем прерывание по совпадению TIMSK |= (1<<OCIE1A); //разрешаем автоматическое обнуление счетного регистра при совпадении TCCR1B |= (1<<WGM12); //обнуляем счетный регистр TCNT1 = 0; //записываем в счетный регистр значение кличества тактов равное одной секунде OCR1A = 31250; } ISR(TIMER1_COMPA_vect) { sec++; if (sec == 60) { sec = 0; min++; } else if (min == 60) { min = 0; hour++; } } //---------- //---------- прерывания---------------------------------------------------- void External_interrupts_pin_setup(void) { DDRD &= ~((1<<3) | (1<<2)); PORTD |= (1<<3) | (1<<2); } void External_interrupts_setup(void) { //настройка прерывания INT0 по спаду MCUCR |= (1<<ISC01); MCUCR &= ~(1<<ISC00); //настройка прерывания INT1 по спаду MCUCR |= (1<<ISC11); MCUCR &= ~(1<<ISC10); //разрешаем внешние прерывания INT0 и INT1 GICR |= (1<<INT1) | (1<<INT0); } ISR(INT0_vect) //макрос обработки прерывания, изменение отображаемой информации { if (++button_1 > 3) button_1 = 1; } ISR(INT1_vect) { } //---------- //---------- void ADC_pin_setup(void) { DDRC &= ~((1<<5) | (1<<4)); //пин PD4 и PD5 в режим работы вход PORTC &= ~((1<<5) | (1<<4)); //высокое входное сопротивление на пинах PD4 и PD5 } void ADC_setup() { //разрешаем работу АЦП ADCSRA |= (1<<ADEN); //непрерывный режим работы АЦП ADCSRA |= (1<<ADFR); //частота дискретизации 125 кГц (частота МК 8 МГЦ, делитель 64) ADCSRA |= (1<<ADPS2) | (1<<ADPS1); ADCSRA &= ~(1<<ADPS0); //подключаем внешний ИОН - 5В //ADMUX |= (1<<REFS0); //ADMUX &= ~(1<<REFS1); //подключаем внутренний ИОН - 2,56В ADMUX |= (1<<REFS1) | (1<<REFS0); //выравнивание результата преобразования в регистре ADC по правой стороне ADMUX &= ~(1<<ADLAR); //настраиваем 5-й канал АЦП ADMUX |= (1<<MUX2) | (1<<MUX0); ADMUX &= ~((1<<MUX3) | (1<<MUX1)); //разрешаем преобразование АЦП ADCSRA |= (1<<ADSC); //разрешаем прерывание от АЦП ADCSRA |= (1<<ADIE); } void ADC_set_chanel(unsigned char chanel) //функция выбора канала АЦП { switch(chanel) { case 0: //4-й канал ADMUX |= (1<<MUX2); ADMUX &= ~((MUX3) | (MUX1) | (MUX0)); break; case 1: //5-й канал ADMUX |= (1<<MUX2) | (1<<MUX0); ADMUX &= ~((1<<MUX3) | (1<<MUX1)); } } ISR(ADC_vect) { n_ADC++; //этотвариант работает if (n_ADC == 1) { temp = (ADC*2.56/1024)*100; } else if (n_ADC == 2) { volt = (ADC*2.56/1024.0*5.3)*100; n_ADC = 0; } ADC_set_chanel(n_ADC); } //---------- int main(void) { LED_DISP_pin_setup(); Timer0_setup(); Timer1_setup(); External_interrupts_pin_setup(); External_interrupts_setup(); ADC_pin_setup(); ADC_setup(); sei(); //глобальное разрешение прерываний while (1) { if (button_1 == 1) { show_min_sec(min, sec); } else if (button_1 == 2) { show_temp(temp); } else if (button_1 == 3) { show_volt(volt); } } } После включения, при нажатии на кнопку (подключена к пину PD2) изменяется отображаемая информация на семисегментном индикаторе. Поле первого нажатия отображается время прошедшее с момента включения, после второго - температура, после третьего - напряжение на АКБ. И вот тут возник вопрос. А как включить десятичную точку во втором разряде при отображении напряжения? |
Автор: | Starichok51 [ Сб сен 28, 2024 18:18:52 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
так добавь точку к цифре по ИЛИ. |
Автор: | ks0 [ Сб сен 28, 2024 20:37:58 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Очень у вас хорошо читаемый код получился. Хотя могут, конечно, набежать и сказать, что не по феншую, и какие-то непонятные константы в тексте тут и там) По мне так лучше держать сразу отображаемый код в переменных, а не цифру от 0 до 9. Хоть у вас и в двух разных регистрах сегменты, но все равно по номерам битов от 0 до 7 - простой char получается. Лучше переделать иначе с точкой будет слишком кучеряво. Я последний раз точку делал так: Код: char get_code(char c, char pt)
{ if(pt) pt=0b10000000; // добавить точку switch(c) { case 0: return 0b00111111 | pt; |
Автор: | Martian [ Сб сен 28, 2024 20:53:04 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Если занести всё в массив, то вместо кучи хорошо читаемых строчек switch(c) { case 0... была бы одна плохо читаемая PORTB |= MyArray[c]; |
Автор: | shonty [ Сб сен 28, 2024 21:57:03 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
народ до сих пор динамикой занимается.. есть копеечные готовые модули типа MAX7219, TM1637 и др.. |
Автор: | Thinnnfor [ Сб сен 28, 2024 21:59:01 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
MAX7219-это круто , это просто ! TM1637 это какое то дерьмище вообще не получилось ничего ... |
Автор: | shonty [ Сб сен 28, 2024 22:03:03 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Thinnnfor писал(а): TM1637 это какое то дерьмище вообще не поличилось ничего ... если не получилось - не значит, что дермище)) вручную интерфейс мутить нужно |
Автор: | Martian [ Сб сен 28, 2024 22:04:07 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
а не поличилось, патамучто "GyverTM1637 — бибилотека для 7 сегментного дисплея на чипе TM1637 с кучей приколюх" (орфография сохранена) и пака одна дурака макака совитует хирню, дргая дурака макака не мажит то же думот. да здраствуят адурина! с кучей приколюх |
Автор: | Thinnnfor [ Сб сен 28, 2024 22:15:38 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Я не пользуюсь библиотеками , тем более ардуино ! Ардуино не пользуюсь из принципа ! У меня CV AVR ! Добавлено after 5 minutes 3 seconds: Re: ATmega8, динамическая индикация, switch case и десятичная то CV AVR для авр, для микрочипов PIC CCS |
Автор: | shonty [ Сб сен 28, 2024 22:16:17 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Martian, ты увенный и сам себе веришь) если что я асме пишу) |
Автор: | Martian [ Сб сен 28, 2024 22:17:09 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
У-ух! (почесал себе зад) |
Автор: | OKF [ Сб сен 28, 2024 22:29:07 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Не перевелись ведь люди в русских селеньях! |
Автор: | Thinnnfor [ Сб сен 28, 2024 22:29:52 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
shonty писал(а): если что я асме пишу) Ну ....респект и уважуха !!! |
Автор: | OKF [ Сб сен 28, 2024 22:32:47 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Дурак дураком. Соболезную. |
Автор: | Thinnnfor [ Сб сен 28, 2024 22:39:59 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Ассемблер - это круто ! Добавлено after 56 seconds: Re: ATmega8, динамическая индикация, switch case и десятичная то Когда то под z80 тоже писал , давно это было ! |
Автор: | shonty [ Сб сен 28, 2024 23:01:04 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Martian писал(а): У-ух! (почесал себе зад) OKF писал(а): Дурак дураком. Соболезную. а что вы такие все взволнованные? ![]() ![]() ![]() |
Автор: | Thinnnfor [ Сб сен 28, 2024 23:38:33 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Всё норм ! динамическая индикация , индицирует динамически ! Всё хорошо !! |
Автор: | Базилюк [ Вс сен 29, 2024 06:46:43 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Вообще, это обычный путь начинающего - одиночные светодиоды, семисегментный индикатор в один разряд, и наконец - динамическая индикация на семисегментниках. Всё по классике, это же изучение. Затем должен быть двустрочный знакосинтезирующий ЖК-дисплей, желательно не на I2C, а на параллельной шине. А вот ассемблер нынче не нужен. Его можно знать, но писать на нем - смысла нет никакого. |
Автор: | shonty [ Вс сен 29, 2024 07:20:30 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Базилюк писал(а): А вот ассемблер нынче не нужен. Его можно знать, но писать на нем - смысла нет никакого. То, что я пишу на асме, я бы и не стал здесь упоминать, это не тема данного обсуждения.Сказал лишь для того, что бы развеять "уверенность" мартиана что все сидят на ардуине и на библиотеках: Martian писал(а): а не поличилось, патамучто "GyverTM1637 — бибилотека для 7 сегментного дисплея на чипе TM1637 с кучей приколюх" (орфография сохранена) к чему эта реплика вообще? и пака одна дурака макака совитует хирню, дргая дурака макака не мажит то же думот. да здраствуят адурина! с кучей приколюх ![]() По поводу есть смысл или нет, то это обычный холивар на тему асм/яву, гимп/фотошоп, линукс/виндовс... А писАть я могу хоть на тетрадке в клеточку, главное результат. ![]() |
Автор: | Базилюк [ Вс сен 29, 2024 08:26:45 ] |
Заголовок сообщения: | Re: ATmega8, динамическая индикация, switch case и десятична |
Ардуина существует уже больше 15 лет, поэтому немудрено, что многие её используют. Я вот например использую готовые платы от WeAct, китайцы научились ставить на них мощные МК. По поводу затронутой темы с дин.идникацией. Я тоже в своих первых опытах писал нечто подобное ![]() То есть, примерно так: Код: /* Распиновка сегментов на одном порту (можно в любом порядке пинов) */ #define SEGA (1 << 0) #define SEGB (1 << 1) #define SEGC (1 << 2) #define SEGD (1 << 3) #define SEGE (1 << 4) #define SEGF (1 << 5) #define SEGG (1 << 6) #define SEGp (1 << 7) /* Сборка сегментов в символ семисегментника */ #define CH0 (SEGA | SEGB | SEGC | SEGD | SEGE | SEGF | SEGG) #define CH1 (SEGA | SEGB ) #define CH2 (SEGA | SEGB | SEGD | SEGE | SEGG) #define CH3 (SEGA | SEGB | SEGC | SEGD | SEGG) #define CH4 ( SEGB | SEGC | SEGF | SEGG) #define CH5 (SEGA | SEGC | SEGD | SEGF | SEGG) #define CH6 (SEGA | SEGC | SEGD | SEGE | SEGF | SEGG) #define CH7 (SEGA | SEGB | SEGC ) #define CH8 (SEGA | SEGB | SEGC | SEGD | SEGE | SEGF | SEGG) #define CH9 (SEGA | SEGB | SEGC | SEGD | SEGF | SEGG) #define SEG_OFF 0 /* Распиновка разрядов (можно в любом порядке пинов) */ #define D0 (1 << 0) #define D1 (1 << 1) #define D2 (1 << 2) #define D3 (1 << 3) #define ALLDIGIT_OFF GPIOB = D0 | D1 | D2 | D3 /** * Получение списка включаемых пинов для сегментов символа * @param ch - отображаемая цифра (0 - 9) * @return Значение для записи в выходной порт */ uint8_t GetSegments(uint8_t ch) { const uint8_t digits[10] = {CH0, CH1, CH2, CH3, CH4, CH5, CH6, CH7, CH8, CH9}; return digits[ch]; } /** * Фаза дин.индикации. Отображение цифры в указанном разряде * @param digit - номер разряда индикатора * @param ch - отображаемая цифра * @param dot - признак десятичной точки */ void Phase(uint8_t digit, uint8_t ch, bool dot) { ALLDIGIT_OFF; // выключение всех разрядов GPIOA = GetSegments(ch); // выходы сегментов /* добавление в порт десятичной точки */ if(dot) GPIOA |= SEGp; /* Выбор разряда */ switch(digit) { case 0: GPIOB &= ~D0; // включение разряда 0 break; case 1: GPIOB &= ~D1; // включение разряда 1 break; case 2: GPIOB &= ~D2; // включение разряда 2 break; case 3: GPIOB &= ~D3; // включение разряда 3 break; } } (GPIOA и GPIOB написаны условно) И затем функцию Phase() вызывать через заданные промежутки времени в соответствии с порядком индикации (можно даже и в любом порядке разрядов). В функцию передаем номер выбираемого разряда, отображаемую цифру и признак включения десятичной точки в разряде. Да, в эту функцию можно еще добавить параметр - признак гашения цифры, и по этому признаку гасить все сегменты в разряде, то есть, не отображать его. |
Страница 1 из 5 | Часовой пояс: UTC + 3 часа |
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group http://www.phpbb.com/ |