реклама на сайте
подробности

 
 
17 страниц V  « < 15 16 17  
Reply to this topicStart new topic
> Микроконтроллеры для начинающих, AVR, PIC, FUJITSU
Plain
сообщение Aug 23 2018, 11:26
Сообщение #241


Гуру
******

Группа: Участник
Сообщений: 6 776
Регистрация: 5-03-09
Из: Москва
Пользователь №: 45 710



Цитата(lyric @ Aug 23 2018, 11:44) *
Функция eeprom_update_word() сама этого не делает?

Если не делает, то её фактически нет, разве что какому-то программисту от микроконтроллера понадобится только его EEPROM и ничего более.

На время подачи сигнала разблокирования записи в EEPROM прерывания требуется запретить, чтобы выполнить требования по разблокирующей последовательности (у микроконтроллеров PIC, например, это последовательная запись 55 и AA в регистр разблокировки), но далее, на саму запущенную процедуру записи, любая работа программы никакого влияния не оказывает, в т.ч. и её работа в прерываниях.
Go to the top of the page
 
+Quote Post
lyric
сообщение Sep 12 2018, 05:27
Сообщение #242





Группа: Участник
Сообщений: 14
Регистрация: 29-01-16
Пользователь №: 90 250



Снова здравствуйте.

AVR.

Есть 2 самописных функции.
Эти функции используют разные глобальные переменные, вообще никак не пересекаются между собой. Вызываются в оновном цикле, никак не завязаны на прерывания. В одной из них работа с SPI, в другой с АЦП.
Но при этом функция с АЦП влияет на работу функции с SPI. Нашёл 2 строчки из-за которых это происходит, но там просто математические вычисления, никакого отношения не имеющие к другой функции.

При включении любого уровня оптимизации это проявляется. На уровне -О0 всё работает нормально.

Подскажите в чём может быть дело?

Сообщение отредактировал lyric - Sep 12 2018, 05:27
Go to the top of the page
 
+Quote Post
DASM
сообщение Sep 12 2018, 06:12
Сообщение #243


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



код нужен
Go to the top of the page
 
+Quote Post
lyric
сообщение Sep 12 2018, 07:53
Сообщение #244





Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
DASM
сообщение Sep 12 2018, 08:28
Сообщение #245


Гуру
******

Группа: Свой
Сообщений: 3 644
Регистрация: 28-05-05
Пользователь №: 5 493



calibr_ADC_max_AI2 - calibr_ADC_min_AI2 у вас неинициализированы, а в этих строках вы делите на их разность, оная будет равна 0, так они в стартапе обе обнуляются.
Go to the top of the page
 
+Quote Post
lyric
сообщение Sep 12 2018, 10:05
Сообщение #246





Группа: Участник
Сообщений: 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 индикатора, а не один.
Так и есть? или это бред?

help.gif help.gif help.gif

Сообщение отредактировал lyric - Sep 12 2018, 09:45
Go to the top of the page
 
+Quote Post

17 страниц V  « < 15 16 17
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th April 2024 - 01:20
Рейтинг@Mail.ru


Страница сгенерированна за 0.0145 секунд с 7
ELECTRONIX ©2004-2016