|
|
|
Микроконтроллеры для начинающих, AVR, PIC, FUJITSU |
|
|
|
Aug 23 2018, 11:26
|
Гуру
Группа: Участник
Сообщений: 6 776
Регистрация: 5-03-09
Из: Москва
Пользователь №: 45 710
|
Цитата(lyric @ Aug 23 2018, 11:44) Функция eeprom_update_word() сама этого не делает? Если не делает, то её фактически нет, разве что какому-то программисту от микроконтроллера понадобится только его EEPROM и ничего более. На время подачи сигнала разблокирования записи в EEPROM прерывания требуется запретить, чтобы выполнить требования по разблокирующей последовательности (у микроконтроллеров PIC, например, это последовательная запись 55 и AA в регистр разблокировки), но далее, на саму запущенную процедуру записи, любая работа программы никакого влияния не оказывает, в т.ч. и её работа в прерываниях.
|
|
|
|
|
Sep 12 2018, 05:27
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250
|
Снова здравствуйте.
AVR.
Есть 2 самописных функции. Эти функции используют разные глобальные переменные, вообще никак не пересекаются между собой. Вызываются в оновном цикле, никак не завязаны на прерывания. В одной из них работа с SPI, в другой с АЦП. Но при этом функция с АЦП влияет на работу функции с SPI. Нашёл 2 строчки из-за которых это происходит, но там просто математические вычисления, никакого отношения не имеющие к другой функции.
При включении любого уровня оптимизации это проявляется. На уровне -О0 всё работает нормально.
Подскажите в чём может быть дело?
Сообщение отредактировал lyric - Sep 12 2018, 05:27
|
|
|
|
|
Sep 12 2018, 07:53
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250
|
Цитата(DASM @ Sep 12 2018, 13:12) код нужен CODE #define F_CPU 8000000 #include <avr/io.h> #include <stdlib.h> #include <math.h> #include <avr/interrupt.h>
//--------------------------------------------------------------------------------------------------------------глобальные переменные----------------------------------------------------------------- volatile uint8_t R1=0, R2=0, R3=0, R4=0, R5=0, R6=0, R7=0, R8=0; //Переменные значений разрядов индикатора volatile int16_t ADC_AI_1, ADC_AI_2; //Текущие значения АЦП без фильтрации volatile float ADC_AI_1_ff, ADC_AI_2_ff, AI_1, AI_2, AI_1_fv, AI_2_fv;//Текущие значения АЦП после фильтрации, аппроксимированных значений аналоговых входов до коррекции и после volatile int32_t accu1=0, accu2=0; //переменные для оверсемплинга АЦП volatile uint8_t accu_count1=0, accu_count2=0; //переменные для оверсемплинга АЦП volatile int16_t koeff_AI1=1; volatile int16_t koeff_AI2=1; volatile uint8_t DI_portD_Mask; volatile uint8_t DI_portA_Mask_no_opros; volatile uint8_t DI_portA_Mask;
uint8_t tip_AI1=1; uint16_t calibr_ADC_min_AI1; // Калибровочное минимальное значение АЦП аналогового входа AI1 uint16_t calibr_ADC_max_AI1; // Калибровочное максимальное значение АЦП аналогового входа AI1 int16_t NPI_AI1; // Нижний предел измерения параметра с аналогового входа AI1 int16_t VPI_AI1; // Верхний предел измерения параметра с аналогового входа AI1 uint16_t koef_A_AI1; // Коэффициент коррекции А для параметра с аналогового входа AI1 int16_t koef_B_AI1; // Коэффициент коррекции B для параметра с аналогового входа AI1 uint8_t koef_filtra_AI1; // Коэффициент фильтрации параметра с AI1
uint8_t tip_AI2=2; uint16_t calibr_ADC_min_AI2; // Калибровочное минимальное значение АЦП аналогового входа AI2 uint16_t calibr_ADC_max_AI2; // Калибровочное максимальное значение АЦП аналогового входа AI2 int16_t NPI_AI2; // Нижний предел измерения параметра с аналогового входа AI2 int16_t VPI_AI2; // Верхний предел измерения параметра с аналогового входа AI2 uint16_t koef_A_AI2; // Коэффициент коррекции А для параметра с аналогового входа AI2 int16_t koef_B_AI2; // Коэффициент коррекции B для параметра с аналогового входа AI2 uint8_t koef_filtra_AI2; // Коэффициент фильтрации параметра с AI2
//------------------------------------------------------------------------------------------------
void preset()//функция установки портов { //инициализация порта В DDRB = 0b10110000; //конфигурация: 0 - вход. 1 - выход PORTB = 0b01001111; //1 - включение подтягивающих резисторов для входов. 0 - задание выходам порта начальных значений ("отключено" - высокий уровень, "включено" - низкий уровень). //инициализация порта C DDRC = 0b11111111; //конфигурация: 0 - вход. 1 - выход PORTC = 0b01111111; //1 - включение подтягивающих резисторов для входов. 0 - задание выходам порта начальных значений ("отключено" - высокий уровень, "включено" - низкий уровень). //инициализация порта D //конфигурация: 0 - вход: DDRD &=~(1<<PD7); //Настраиваем ножку PD7 в режим входа DDRD &=~(1<<PD6); //Настраиваем ножку PD6 в режим входа DDRD &=~(1<<PD5); //Настраиваем ножку PD5 в режим входа DDRD &=~(1<<PD4); //Настраиваем ножку PD4 в режим входа DDRD &=~(1<<PD3); //Настраиваем ножку PD3 в режим входа DDRD |=(1<<PD2); //Настраиваем ножку PD3 в режим вЫхода //1 - включение подтягивающих резисторов для входов порта D: PORTD |= (1<<PD7); PORTD |= (1<<PD6); PORTD |= (1<<PD5); PORTD |= (1<<PD4); PORTD |= (1<<PD3); //1 - задание выходу №2 порта D начального значения "отключено" - высокий уровень: PORTD |= (1<<PD2); }
void symboll(uint8_t symm) //функция отображения символов на индикаторах { switch(symm) { case 1: SPDR = 0b10111011; break; //цифра 1 case 2: SPDR = 0b10001100; break; //цифра 2 case 3: SPDR = 0b10101000; break; //цифра 3 case 4: SPDR = 0b00111001; break; //цифра 4 case 5: SPDR = 0b01101000; break; //цифра 5 case 6: SPDR = 0b01001000; break; //цифра 6 case 7: SPDR = 0b10111010; break; //цифра 7 case 8: SPDR = 0b00001000; break; //цифра 8 case 9: SPDR = 0b00101000; break; //цифра 9 case 0: SPDR = 0b00001010; break; //цифра 0 case 11: SPDR = 0b10110011; break; //цифра 1 с точкой case 12: SPDR = 0b10000100; break; //цифра 2 с точкой case 13: SPDR = 0b10100000; break; //цифра 3 с точкой case 14: SPDR = 0b00110001; break; //цифра 4 с точкой case 15: SPDR = 0b01100000; break; //цифра 5 с точкой case 16: SPDR = 0b01000000; break; //цифра 6 с точкой case 17: SPDR = 0b10110010; break; //цифра 7 с точкой case 18: SPDR = 0b00000000; break; //цифра 8 с точкой case 19: SPDR = 0b00100000; break; //цифра 9 с точкой case 10: SPDR = 0b00000010; break; //цифра 0 с точкой case 20: SPDR = 0b00011000; break; //буква А case 21: SPDR = 0b01001001; break; //буква B case 22: SPDR = 0b01001110; break; //буква C case 23: SPDR = 0b10001001; break; //буква D case 24: SPDR = 0b01001100; break; //буква E case 25: SPDR = 0b01001010; break; //буква G case 26: SPDR = 0b11001110; break; //буква I case 27: SPDR = 0b00010001; break; //буква K case 28: SPDR = 0b01001111; break; //буква L case 29: SPDR = 0b11011001; break; //буква N case 30: SPDR = 0b11001001; break; //буква O case 31: SPDR = 0b11000001; break; //буква O с точкой case 32: SPDR = 0b00011100; break; //буква P case 33: SPDR = 0b11101111; break; //нижнее подчёркивание case 34: SPDR = 0b11111101; break; //минус case 35: SPDR = 0b11111111; break; //ничего case 36: SPDR = 0b10111110; break; //стрелка вверх case 37: SPDR = 0b11001111; break; //стрелка вниз case 38: SPDR = 0b11011101; break; //буква R case 39: SPDR = 0b11010101; break; //буква R с точкой case 40: SPDR = 0b01101000; break; //буква S case 41: SPDR = 0b01100000; break; //буква S с точкой case 42: SPDR = 0b01001101; break; //буква T case 43: SPDR = 0b11001011; break; //буква U case 44: SPDR = 0b00001011; break; //буква V case 45: SPDR = 0b11110001; break; //буква Z default: SPDR = 0b11111111; //ничего } }
void SPI_init() { SPCR = ((1<<SPE)|(1<<MSTR)); }
void ADC_init() { ADCSRA |= ((1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)); //Разрешение использования АЦП и делитель 64 (частота опроса 125кГц) ADMUX=0; }
void ADC_convert(void) //функция чтения каналов АЦП. Первые 2 канала - это аналогоые входы. Остальные 6 каналов - используются как дискретные входы. { uint16_t kod_acp=0; uint8_t lock_0=0; //чтобы за один вызов функции выполнялось только одно преобразование АЦП, а не 0 и 7 в один раз static float prom_out1=0, prom_out2=0; unsigned char savee = SREG;
if (ADMUX==7) { ADCSRA |= (1<<ADSC); //Начинаем преобразование while((ADCSRA & (1<<ADSC))) {}; //проверка закончилось ли аналого-цифровое преобразование savee =SREG; cli (); kod_acp = (unsigned int) ADC; if (kod_acp<300) {DI_portA_Mask_no_opros |= 0b00100000;} else {DI_portA_Mask_no_opros &= 0b11011111;} lock_0=1; SREG= savee; ADMUX=0; }
if (ADMUX==6) { ADCSRA |= (1<<ADSC); //Начинаем преобразование while((ADCSRA & (1<<ADSC))) {}; //проверка закончилось ли аналого-цифровое преобразование savee =SREG; cli (); kod_acp = (unsigned int) ADC; if (kod_acp<300) {DI_portA_Mask_no_opros |= 0b00010000;} else {DI_portA_Mask_no_opros &= 0b11101111;} SREG= savee; ADMUX=7; }
if (ADMUX==5) { ADCSRA |= (1<<ADSC); //Начинаем преобразование while((ADCSRA & (1<<ADSC))) {}; //проверка закончилось ли аналого-цифровое преобразование savee =SREG; cli (); kod_acp = (unsigned int) ADC; if (kod_acp<300) {DI_portA_Mask_no_opros |= 0b00001000;} else {DI_portA_Mask_no_opros &= 0b11110111;} SREG= savee; ADMUX=6; }
if (ADMUX==4) { ADCSRA |= (1<<ADSC); //Начинаем преобразование while((ADCSRA & (1<<ADSC))) {}; //проверка закончилось ли аналого-цифровое преобразование savee =SREG; cli (); kod_acp = (unsigned int) ADC; if (kod_acp<300) {DI_portA_Mask_no_opros |= 0b00000100;} else {DI_portA_Mask_no_opros &= 0b11111011;} SREG= savee; ADMUX=5; }
if (ADMUX==3) { ADCSRA |= (1<<ADSC); //Начинаем преобразование while((ADCSRA & (1<<ADSC))) {}; //проверка закончилось ли аналого-цифровое преобразование savee =SREG; cli (); kod_acp = (unsigned int) ADC; if (kod_acp<300) {DI_portA_Mask_no_opros |= 0b00000010;} else {DI_portA_Mask_no_opros &= 0b11111101;} SREG= savee; ADMUX=4; }
if (ADMUX==2) { ADCSRA |= (1<<ADSC); //Начинаем преобразование while((ADCSRA & (1<<ADSC))) {}; //проверка закончилось ли аналого-цифровое преобразование savee =SREG; cli (); kod_acp = (unsigned int) ADC; if (kod_acp<300) {DI_portA_Mask_no_opros |= 0b00000001;} else {DI_portA_Mask_no_opros &= 0b11111110;} SREG= savee; ADMUX=3; }
if (ADMUX==1) { ADCSRA |= (1<<ADSC); //Начинаем преобразование while((ADCSRA & (1<<ADSC))) {}; //проверка закончилось ли аналого-цифровое преобразование savee =SREG; cli (); accu2 += (int32_t) ADC;//Оверсемплинг AI2. Было 10 бит, стало 13 accu_count2++; if (accu_count2>=64) { ADC_AI_2=(int16_t)(accu2/8); accu_count2=0; accu2=0;//фильтрация AI2 ADC_AI_2_ff=prom_out2+(ADC_AI_2-prom_out2)/(float)koef_filtra_AI2; //экспоненциальный фильтр prom_out2=ADC_AI_2_ff; if (tip_AI2==1) { AI_2= ((float)((ADC_AI_2_ff-calibr_ADC_min_AI2)/(calibr_ADC_max_AI2-calibr_ADC_min_AI2)) * (((float)(VPI_AI2-NPI_AI2))/koeff_AI2)+ ((float)(NPI_AI2/koeff_AI2)));//Аппроксимация AI2 AI_2_fv=AI_2*(((float)koef_A_AI2)/1000)+(float)koef_B_AI2/koeff_AI2; //Коррекция AI2 } else {AI_2=0;AI_2_fv=0;} } SREG= savee; ADMUX=2; }
if ((ADMUX==0) && (lock_0==0)) { ADCSRA |= (1<<ADSC); //Начинаем преобразование while((ADCSRA & (1<<ADSC))) {}; //проверка закончилось ли аналого-цифровое преобразование savee =SREG; cli (); accu1 += (int32_t) ADC; //Оверсемплинг AI1. Было 10 бит, стало 13 accu_count1++; if (accu_count1>=64) { ADC_AI_1=(int16_t)(accu1/8); accu_count1=0; accu1=0;//фильтрация AI1 ADC_AI_1_ff=prom_out1+(ADC_AI_1-prom_out1)/(float)koef_filtra_AI1; //экспоненциальный фильтр prom_out1=ADC_AI_1_ff; if ((tip_AI1>0) && (tip_AI1<4)) { AI_1= ((float)((ADC_AI_1_ff-calibr_ADC_min_AI1)/(calibr_ADC_max_AI1-calibr_ADC_min_AI1)) * (((float)(VPI_AI1-NPI_AI1))/koeff_AI1)+ ((float)(NPI_AI1/koeff_AI1)));//Аппроксимация AI1 AI_1_fv=AI_1*(((float)koef_A_AI1)/1000)+(float)koef_B_AI1/koeff_AI1;//Коррекция AI1 } else {AI_1=0;AI_1_fv=0;} } SREG= savee; ADMUX=1; } lock_0=0;
}
void indi() { static char n_count=1; //Переменная для перебора посылаемых байтов-символов на разряды индикатора if (n_count==8) {symboll(R8); while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся SPDR =0b01111111;//выбор индикатора while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся //отрицательный фронт для записи в STORAGE REGISTER PORTB |= (1<<4); // высокий уровень PORTB &= ~(1<<4); // низкий уровень }
if (n_count==7) { symboll(R7); while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся SPDR =0b10111111;//выбор индикатора while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся //отрицательный фронт для записи в STORAGE REGISTER PORTB |= (1<<4); // высокий уровень PORTB &= ~(1<<4); // низкий уровень }
if (n_count==6) {symboll(R6); while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся SPDR =0b11011111;//выбор индикатора while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся //отрицательный фронт для записи в STORAGE REGISTER PORTB |= (1<<4); // высокий уровень PORTB &= ~(1<<4); // низкий уровень }
if (n_count==5) {symboll(R5); while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся SPDR =0b11101111;//выбор индикатора while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся //отрицательный фронт для записи в STORAGE REGISTER PORTB |= (1<<4); // высокий уровень PORTB &= ~(1<<4); // низкий уровень }
if (n_count==4) {symboll(R4); while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся SPDR =0b11110111;//выбор индикатора while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся //отрицательный фронт для записи в STORAGE REGISTER PORTB |= (1<<4); // высокий уровень PORTB &= ~(1<<4); // низкий уровень }
if (n_count==3) {symboll(R3); while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся SPDR =0b11111011;//выбор индикатора while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся //отрицательный фронт для записи в STORAGE REGISTER PORTB |= (1<<4); // высокий уровень PORTB &= ~(1<<4); // низкий уровень }
if (n_count==2) {symboll(R2); while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся SPDR =0b11111101;//выбор индикатора while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся //отрицательный фронт для записи в STORAGE REGISTER PORTB |= (1<<4); // высокий уровень PORTB &= ~(1<<4); // низкий уровень }
if (n_count==1) {symboll(R1); while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся SPDR =0b11111110;//выбор индикатора while (!(SPSR & (1<<SPIF))) {}; //ожидание, пока данные передадутся //отрицательный фронт для записи в STORAGE REGISTER PORTB |= (1<<4); // высокий уровень PORTB &= ~(1<<4); // низкий уровень }
++n_count; if (n_count>8) {n_count=1;} }
int main(void) { preset(); SPI_init(); ADC_init(); sei(); while (1) { ADC_convert(); R1=7; R2=7; R3=7; R4=7; R5=7; R6=7; R7=7; R8=7; indi(); }//КОНЕЦ ОСНОВНОГО ЦИКЛА while }//КОНЕЦ ОСНОВНОЙ ФУНКЦИИ main
Функция ADC_convert() влияет на работу функции indi(). ADC_convert() - опрос 8 каналов АЦП, indi() - индикация на 8-разрядный семисегментный экран по SPI. Проблема - последний разряд (R8) мерцает, в то время как остальные разряды горят нормально. Это не вся программа, только те её части, с которыми проблема. Код компилится (Atmel Studio 7) и проблема в нём проявляется. 2 строчки, выделенные жирным цветом - если их закомментировать, то мерцание пропадает. Какое отношение они имеют к индикации - непонятно, но влияют. Такие же две строчки есть и чуть выше в этой же функции, только с другими переменными работают, - и они почему-то никак не влияют на работу других частей программы.
Сообщение отредактировал lyric - Sep 12 2018, 08:05
|
|
|
|
|
Sep 12 2018, 10:05
|
Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250
|
Цитата(DASM @ Sep 12 2018, 15:28) calibr_ADC_max_AI2 - calibr_ADC_min_AI2 у вас неинициализированы, а в этих строках вы делите на их разность, оная будет равна 0, так они в стартапе обе обнуляются. Все переменные инициализировал, ничего не изменилось. Ну и прошу прощения, - ошибся: Присмотрелся лучше к экрану - мерцания прекращаются только если ADC_convert вообще не вызывать. Что-то не так с этой функцией (подскажите что?). И почему она портит только один разряд а не все 8 - не пойму. Когда ADMUX=0 и ADMUX=1 функция ADC_convert выполняется дольше, потому что больше расчётов в ней происходит. Поэтому функция indi() в эти моменты дольше НЕ выполняется. И, видимо, эти моменты совпадают с моментами, когда должен включаться индикатор (R8). Но между ADMUX=0 и ADMUX=1 функция indi() всё равно должна успеть выполниться 1 раз, и получается что мерцать должны 2 индикатора, а не один. Так и есть? или это бред?
Сообщение отредактировал lyric - Sep 12 2018, 09:45
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|