Обсуждаем контроллеры компании Atmel.
Ответить

EEPROM запись в цикле.

Пт окт 20, 2017 07:19:22

Столкнулся с проблемкой по работе с ЕЕПРОМом , (провожу симуляцию в протеусе)ж

в еепром должны записаться 1,2. А суда по симуляции в протеусе там хреновина какая та пишется.

Проблема в протеусе или в коде ? может кто подсказать.
Вместо eeprom_write_byte(); , буду использывать eeprom_update_byte();
фулл код:
Спойлер
Код:
#define F_CPU 8000000UL

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
//----------///init_pwm///----------//
void init_pwm()
{
   TCCR0A=(1<<COM0A1) | (0<<COM0A0) | (1<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | (1<<WGM00);
   TCCR0B=(0<<WGM02) | (0<<CS02) | (1<<CS01) | (0<<CS00);
   OCR0A=0x00;
   OCR0B=0x00;

   TCCR1A=(1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (1<<WGM10);
   TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10);
   OCR1AL=0x00;
   OCR1BL=0x00;

   TCCR2A=(1<<COM2A1) | (0<<COM2A0) | (1<<COM2B1) | (0<<COM2B0) | (1<<WGM21) | (1<<WGM20);
   TCCR2B=(0<<WGM22) | (0<<CS22) | (1<<CS21) | (0<<CS20);
   OCR2A=0x00;
   OCR2B=0x00;
}
//----------//
void init_int0()
{
   //настраиваем на срабатывание INT0 по переднему фронту
   EICRA |= (1<<ISC01)|(0<<ISC00);
   //разрешаем внешнее прерывание INT0
   EIMSK |= (1<<INT0);
}
//----------//
void init_io()
{
   DDRB=(0<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(0<<PB5)|(0<<PB6)|(0<<PB7);
   PORTB=0x00;
   DDRC=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3)|(1<<PC4)|(1<<PC5)|(1<<PC6);
   PORTC=0x00;
   DDRD=(1<<PD0)|(1<<PD1)|(1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
   PORTD=0x00;
}
//----------//
//настройка параметров работы функций
#define BTN_LOCK_TIME      30               /*время обработки дребезга в милисекундах (10-100)*/
#define BTN_LONG_TIME      1000            /*время фиксации длинного нажатия в милисекундах (1000 - 2500)*/
//настройки портов
/*порт чтения кнопок*/
#define BTN_PORT         PORTB
#define BTN_DDR            DDRB
#define BTN_PIN            PINB
/*пины чтения кнопок*/
#define BTN_LINE_UP      (1<<7)
#define BTN_LINE_DN      (1<<6)
#define BTN_LINE_POWER   (1<<5)
#define BTN_LINE_SW      (1<<0)
//глобальные переменные
volatile uint8_t BtnFlags;               //байт флагов нажатия кнопки
#define BTN_SHRT_UP         (1<<0)         /*бит короткого нажатия кнопки up*/
#define BTN_SHRT_DN         (1<<1)         /*бит короткого нажатия кнопки dn*/
#define BTN_SHRT_POWER      (1<<2)         /*бит короткого нажатия кнопки POWER */
#define BTN_SHRT_SW         (1<<3)         /*бит короткого нажатия кнопки SW*/
#define BTN_LONG_UP         (1<<4)         /*бит длинного нажатия кнопки up*/
#define BTN_LONG_DN         (1<<5)         /*бит длинного нажатия кнопки dn*/
#define BTN_LONG_SW         (1<<6)         /*бит короткого нажатия кнопки SW*/
//----------
//Функция настройки библиотеки работы с кнопками
void BtnInit (void)
{
   BTN_DDR &= ~(BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_POWER|BTN_LINE_SW);//на ввод
   BTN_PORT |= (BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_POWER|BTN_LINE_SW);//подтяжка вкл
}
//----------
//Функция чтения данных о нажатии кнопок
char BtnGet (void)
{
   cli();
   char temp = BtnFlags;
   BtnFlags = 0;
   sei();
   return temp;
}
//----------
//ФУНКЦИЯ ОБРАБОТКИ НАЖАТИЙ КЛАВИШ (вызывать в прерывании с частотой 100 Гц)
//короткое нажатие устанавливает бит BTN_SHRT_X глобальной переменной BtnFlags
//длинное нажатие устанавливает бит BTN_LONG_X глобальной переменной BtnFlags
void BtnExe (void)
{
   static unsigned char BtnLockBit;            //защелка (защита от дребезга)
   static unsigned char BtnLockCoun;         //счетчик защелки (защита от дребезга)
   static unsigned char BtnLongCoun;         //счетчик длинного нажатия
   static unsigned char BtnLastState;         //последнее состояние кнопок перед отпусканием

   char mask = 0;
   if (! (BTN_PIN & BTN_LINE_UP))      mask = BTN_SHRT_UP;
   if (! (BTN_PIN & BTN_LINE_DN))      mask = BTN_SHRT_DN;
   if (! (BTN_PIN & BTN_LINE_POWER))   mask = BTN_SHRT_POWER;
   if (! (BTN_PIN & BTN_LINE_SW))      mask = BTN_SHRT_SW;

   if (mask){                           //опрос состояния кнопки
      if (BtnLockCoun < (BTN_LOCK_TIME/10)){   //клавиша нажата
         BtnLockCoun++;
         return;                        //защелка еще не дощитала - возврат
      }
      BtnLastState = mask;
      BtnLockBit =1;                     //нажатие зафиксировано
      if (BtnLongCoun >= (BTN_LONG_TIME/10))
      return;                        //возврат, т.к. счетчик длинн нажат досчитал до максимума еще раньше
      if (++BtnLongCoun >= (BTN_LONG_TIME/10))
      BtnFlags |= (BtnLastState<<4);         //счетчик досчитал до максимума - устанавливаем биты длинного нажатия
   }
   else{                              //клавиша отжата
      if (BtnLockCoun){
         BtnLockCoun --;
         return;                        //защелка еще не обнулилась - возврат
      }
      if (! BtnLockBit)                  //СТАТИЧЕСКИЙ ВОЗВРАТ
      return;
      BtnLockBit =0;                     //отжатие зафиксировано
      if (BtnLongCoun < (BTN_LONG_TIME/10))
      BtnFlags |= BtnLastState;         //установка бита короткого нажатия
      BtnLongCoun = 0;               //сброс счетчика длительности нажатия
   }
}
//----------****7SEG****----------
#define SEGA 6
#define SEGB 5
#define SEGC 1
#define SEGD 2
#define SEGE 3
#define SEGF 4
#define SEGG 0

#define ANOD1 4
#define ANOD2 7
#define ANOD3 4
//----------
void segchar (unsigned char seg)
{
   switch (seg)
   {
      case 0:
      PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(1<<SEGG);break;
      case 1:
      PORTC=(1<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break;
      case 2:
      PORTC=(0<<SEGA)|(0<<SEGB)|(1<<SEGC)|(0<<SEGD)|(0<<SEGE)|(1<<SEGF)|(0<<SEGG);break;
      case 3:
      PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(1<<SEGF)|(0<<SEGG);break;
      case 4:
      PORTC=(1<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break;
      case 5:
      PORTC=(0<<SEGA)|(1<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break;
      case 6:
      PORTC=(0<<SEGA)|(1<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(0<<SEGG);break;
      case 7:
      PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break;
      case 8:
      PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(0<<SEGG);break;
      case 9:
      PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break;
      case 99: //OFF Все сегменты
      PORTC=(1<<SEGA)|(1<<SEGB)|(1<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break;
   }
}
unsigned char ValuePWM[]={0,0,0,0,0,0};
unsigned char FlagPower[]={0,0,0,0,0,0};
void UpdateFlagPower(unsigned char ZoneNumber,unsigned char Flag)
{
   FlagPower[ZoneNumber]=Flag;
}

void UpdateValue(void)
{
   for (unsigned char ValueCount = 0; ValueCount < 5; ValueCount++)
   {
      switch (ValueCount)
      {
         case 0:
         OCR0A=ValuePWM[ValueCount]*2.56;break;
         case 1:
         OCR0B=ValuePWM[ValueCount]*2.56;break;
         case 2:
         OCR1AL=ValuePWM[ValueCount]*2.56;break;
         case 3:
         OCR1BL=ValuePWM[ValueCount]*2.56;break;
         case 4:
         OCR2A=ValuePWM[ValueCount]*2.56;break;
         case 5:
         OCR2B=ValuePWM[ValueCount]*2.56;break;
      }
   }
}
unsigned char data1 = 0;
unsigned char data2 = 0;
unsigned char count = 0;
unsigned char ZoneNumber=0;
void WriteSeg(unsigned char Number)
{
   data1=ValuePWM[Number]%10;
   data2=ValuePWM[Number]/10;
   PORTB |=(1<<ANOD1);
   PORTD |=(1<<ANOD2);
   PORTD |=(1<<ANOD3);
   segchar(99);
   count++;
   if (count==1){
      PORTB &= ~(1<<ANOD1);
      segchar(data1);
      PORTD |=(1<<ANOD2);
      PORTD |=(1<<ANOD3);
   }
   if (count==2){
      PORTD &= ~(1<<ANOD2);
      segchar(data2);
      PORTB |=(1<<ANOD1);
      PORTD |=(1<<ANOD3);
   }
   if (count==3){
      PORTD &= ~(1<<ANOD3);
      segchar(Number+1);
      PORTB |=(1<<ANOD1);
      PORTD|=(1<<ANOD2);
   }
   if (count==3){count=0;}
}
ISR(INT0_vect)
{
   WriteSeg(ZoneNumber);
   UpdateValue();
   BtnExe();
}
unsigned char fBtnPower=0;
void BtnUpdate(void)
{
   char BtnMask = BtnGet ();
   if (BtnMask == BTN_SHRT_POWER)
   {
   }
   if ((BtnMask == BTN_SHRT_SW))
   {
      ZoneNumber++;
      if (ZoneNumber==6)
      {
         ZoneNumber=0;
      }
   }
   //одиночное нажатие +
   if ((BtnMask == BTN_SHRT_UP)& (ValuePWM[ZoneNumber] < 99))
   {
      ValuePWM[ZoneNumber]++;
   }
   //одиночное нажатие -
   if ((BtnMask == BTN_SHRT_DN)& (ValuePWM[ZoneNumber] > 0))
   {
      ValuePWM[ZoneNumber]--;
   }
   //Удержание +
   if ((BtnMask == BTN_LONG_UP) & (ValuePWM[ZoneNumber] < 99))
   {
      while ((!(PINB&0b10000000))& (ValuePWM[ZoneNumber] < 99))
      {
         ValuePWM[ZoneNumber]++;
         _delay_ms(50);
      }
   }
   //Удержание -
   if ((BtnMask == BTN_LONG_DN) & (ValuePWM[ZoneNumber] > 0))
   {
      while ((!(PINB&0b01000000))& (ValuePWM[ZoneNumber] > 0))
      {
         ValuePWM[ZoneNumber]--;
         _delay_ms(50);
      }
   }
}
//----------

uint8_t EEMEM FlagPower1_EEPROM=0;
uint8_t EEMEM FlagPower2_EEPROM=0;
uint8_t EEMEM FlagPower3_EEPROM=0;
uint8_t EEMEM FlagPower4_EEPROM=0;
uint8_t EEMEM FlagPower5_EEPROM=0;
uint8_t EEMEM FlagPower6_EEPROM=0;

uint8_t EEMEM Value1_EEPROM=0;
uint8_t EEMEM Value2_EEPROM=0;
uint8_t EEMEM Value3_EEPROM=0;
uint8_t EEMEM Value4_EEPROM=0;
uint8_t EEMEM Value5_EEPROM=0;
uint8_t EEMEM Value6_EEPROM=0;

unsigned char LoadingFlagEEPROM(uint8_t NumberZone)
{
   unsigned char PowerFlag=0;
   switch(NumberZone)
   {
      case 1:
      PowerFlag = eeprom_read_byte(&Value1_EEPROM);
      break;
      case 2:
      PowerFlag = eeprom_read_byte(&Value2_EEPROM);
      break;
      case 3:
      PowerFlag = eeprom_read_byte(&Value3_EEPROM);
      break;
      case 4:
      PowerFlag = eeprom_read_byte(&Value4_EEPROM);
      break;
      case 5:
      PowerFlag = eeprom_read_byte(&Value5_EEPROM);
      break;
      case 6:
      PowerFlag = eeprom_read_byte(&Value6_EEPROM);
      break;
   }
   _delay_ms(10);
   return(PowerFlag);
}
uint8_t LoadingValueEEPROM(uint8_t NumberZone)
{
   uint8_t ValueFlag=0;
   switch(NumberZone)
   {
      case 1:
      ValueFlag = eeprom_read_byte(&FlagPower1_EEPROM);
      break;
      case 2:
      ValueFlag = eeprom_read_byte(&FlagPower2_EEPROM);
      break;
      case 3:
      ValueFlag = eeprom_read_byte(&FlagPower3_EEPROM);
      break;
      case 4:
      ValueFlag = eeprom_read_byte(&FlagPower4_EEPROM);
      break;
      case 5:
      ValueFlag = eeprom_read_byte(&FlagPower5_EEPROM);
      break;
      case 6:
      ValueFlag = eeprom_read_byte(&FlagPower6_EEPROM);
      break;
   }
   _delay_ms(10);
   return(ValueFlag);
}

void SaveEEPROM(uint8_t SaveValue,uint8_t SaveFlagPower,uint8_t NumberZone)
{
   switch(NumberZone)
   {
      case 1:
      eeprom_write_byte (&Value1_EEPROM, SaveValue);
      eeprom_write_byte (&FlagPower1_EEPROM, SaveFlagPower);
      break;
      case 2:
      eeprom_write_byte (&Value2_EEPROM, SaveValue);
      eeprom_write_byte (&FlagPower2_EEPROM, SaveFlagPower);
      break;
      case 3:
      eeprom_write_byte (&Value3_EEPROM, SaveValue);
      eeprom_write_byte (&FlagPower3_EEPROM, SaveFlagPower);
      break;
      case 4:
      eeprom_write_byte (&Value4_EEPROM, SaveValue);
      eeprom_write_byte (&FlagPower4_EEPROM, SaveFlagPower);
      break;
      case 5:
      eeprom_write_byte (&Value5_EEPROM, SaveValue);
      eeprom_write_byte (&FlagPower5_EEPROM, SaveFlagPower);
      break;
      case 6:
      eeprom_write_byte (&Value6_EEPROM, SaveValue);
      eeprom_write_byte (&FlagPower6_EEPROM, SaveFlagPower);
      break;
   }
}

//----------
int main(void)
{
   for (unsigned char Count = 0; Count < 5; Count++)
   {
      SaveEEPROM(1,2,Count+1);
      _delay_ms(15);
   }
   
   for (unsigned char Count = 0; Count < 5; Count++)
   {
      FlagPower[Count]=LoadingFlagEEPROM(Count+1);
   }
   
   for (unsigned char Count = 0; Count < 5; Count++)
   {
      ValuePWM[Count]=LoadingValueEEPROM(Count+1);
   }
   init_io();
   init_int0();
   BtnInit();
   init_pwm();
   _delay_ms(10);
   sei();
    while(1)
    {
      BtnUpdate();
   }
   return 0;
}
Последний раз редактировалось 7seg Пт окт 20, 2017 07:45:14, всего редактировалось 1 раз.

Re: EEPROM запись в цикле.

Пт окт 20, 2017 07:28:21

Вот вы эту простыню зачем тут запостили? Вместо неё лучше бы расшифровали, что за фигня у вас пишется вместо 1, 2 - больше толку было бы.
Но скажу вам следующее, возможно, что-то окажется полезным:
1. функций для записи есть несколько: для байта, слова (2 байта), для двойного слова (4 байта) и для блока произвольной длины. выбирайте ту, которая вам больше подходит для данных, и не ломайте голову напрасно
2. функции, содержащие вместо write слово update в своем названии предназначены для продления ресурса записи в EEPROM: прежде чем записать ячейку, эти функции считывают ее и сравнивают с новыми данными - если новые данные не отличаются от уже имеющихся в ячейке, запись не выполняется. так что эти функции работают медленнее, но менее изнашивают EEPROM. повлиять на ваши "чудеса" они не смогут никак.
3. протеус корректно отрабатывает длительность записи в EEPROM (около 4 мс), поэтому при прогоне по шагам программы сразу после выполнения функции записи вы не увидите в дампе EEPROM никакого обновления одного байта, а если писали несколько, то самого последнего записанного. зато спустя 4 мс (по часам симуляции протеуса) увидите

Re: EEPROM запись в цикле.

Пт окт 20, 2017 07:51:00

Есть 3 функции по работе с епромом:
SaveEEPROM(uint8_t SaveValue,uint8_t SaveFlagPower,uint8_t NumberZone)
LoadingValueEEPROM(uint8_t NumberZone)
LoadingFlagEEPROM(uint8_t NumberZone)
Эти функции работают с массивами
unsigned char ValuePWM[]={0,0,0,0,0,0};
unsigned char FlagPower[]={0,0,0,0,0,0};

Массивы в свою очередь содержат данные для 6ти каналов ШИМ и флаг о состоянии канала.

Добавлено after 6 minutes 23 seconds:
причем с 1го по 5тый канал ШИМа значения "2"(SaveEEPROM(1,2,Count+1); Пишется а в 6том канале нет.

Re: EEPROM запись в цикле.

Пт окт 20, 2017 07:55:49

Ужас.
Посмотрел на ваш код - ужас.
У вас switch-ем выбирается, какая переменная пишется/читается - это ж кошмар! Ну поместите все в массив, и пишите элемент массива или сразу весь массив! структуры для этого служат, например... и тогда у вас вся запись превратится в единственный eeprom_update_block, чтение соответственно тоже...

Re: EEPROM запись в цикле.

Пт окт 20, 2017 07:59:13

Изначально все и было в массиве )а ,eeprom_update_block рассматривал как вариант , но не понял его синтаксиса.как правильно записать и считать массив+как изменить(считать ) определенный элемент массива из еепром.

Re: EEPROM запись в цикле.

Пт окт 20, 2017 08:27:52

я не хочу вникать в логику вашего кода, мне проще показать вам абстрактный пример, надеюсь, идею вы уловите и используете.

пусть у нас 6 вариантов конфигурации. каждая конфигурация содержит значения трех параметров. делаем так
Код:
// определяем константу-количество конфигураций
#define CONFIG_CNT 6

// описываем структуру конфигурации
typedef struct{
   int param1;
   char param2;
   long param3;
} configuration;

//определяем массив конфигураций в EEPROM
EEMEM configuration e_config[CONFIG_CNT];

// для удобства такой же массив в ОЗУ
configuration config[CONFIG_CNT];

// вот так конфигурация из ОЗУ сохраняется в EEPROM
eeprom_update_block((void*)config, (void*)e_config, sizeof(config));

// вот так конфигурация считывается в ОЗУ из EEPROM
eeprom_read_block((void*)e_config, (void*)config, sizeof(config)); // я тут ранее опечатался - теперь корректно!!!

// вот так вы получаете параметр из 2-й конфигурации для работы
int var = config[1].param1;
и всё, никаких switch, никакой мороки, никакого гемора... всё будет работать, как часы. код сократится в 10 раз...

Добавлено after 4 minutes 50 seconds:
если вам все-таки приспичит считывать/записывать не весь массив конфигураций, а отдельно взятую конфигурацию из массива, то параметры функций блочной записи/чтения надо всего-навсего сделать такими: ((void*)&config[i], (void*)&e_config[i], sizeof(configuration)), то есть передавать в функцию не адреса и размер массивов целиком, а только адреса нужного элемента и размер структуры этого элемента.

хотя причин так делать я не вижу, разве что экономия нескольких десятков миллисекунд...

Добавлено after 17 minutes 3 seconds:
еще в догонку...
параметры блочных функций такие (по порядку):
-адрес "откуда"
-адрес "куда"
-количество байт
Последний раз редактировалось ARV Пт окт 20, 2017 08:37:20, всего редактировалось 1 раз.

Re: EEPROM запись в цикле.

Пт окт 20, 2017 08:30:01

То есть как я понял ,создаем массив структур e_config[] с типом configuration , который в себя включает нужное количество мне параметров.
Также дублируем этот маcсив в ОЗУ под именем config[](С этими значениями я уже могу работать непосредственно в теле программы).

eeprom_update_block((void*)config, (void*)e_config, sizeof(config));
eeprom_read_block((void*)config, (void*)e_config, sizeof(config));

для чего используется указатель пустого типа ? void* .

Добавлено after 52 seconds:
ARV , большое спасибо за развернутый ответ.

Re: EEPROM запись в цикле.

Пт окт 20, 2017 08:36:08

каждый параметр функции имеет тип. для блочной же функции все равно, какой тип обрабатывать. а вот адрес массива имеет определенный тип, и если вы передадите его в функцию без приведения к void*, то получите варнинг о несоответствии типов. чтобы убрать варнинги, приходится все адреса приводить к типу void* - он считается совместимым с любым иным указателем, и варнинга не будет.

если вас варнинги не нервируют, можете не приводить.

Добавлено after 3 minutes 2 seconds:
7seg писал(а):eeprom_update_block((void*)config, (void*)e_config, sizeof(config));
eeprom_read_block((void*)config, (void*)e_config, sizeof(config));
обратите внимание на приписку о параметрах функций, которую я сделал позже - порядок адресов для чтения и записи - разный! на первом месте адрес массива, откуда берутся данные, на втором - куда помещаются. если вы сделаете так, как процитировано - функция чтения работать не будет

Re: EEPROM запись в цикле.

Пт окт 20, 2017 08:58:27

Еще раз спасибо , сейчас пробую реализовать структуру под мои нужды.

Добавлено after 3 minutes 1 second:
Яж правильно понимаю т.к номера элемента массивов начинаются с 0 , то для 6ти конфигураций мне нужно указать. #define CONFIG_CNT 5.

Добавлено after 6 minutes 49 seconds:
Хотя походу нет при компиляции:
EEPROM Memory Usage : 10 bytes 2,0 % Full

Код:
#define CONFIG_CNT 5
typedef struct
{
   char FlagPower;
   char ValuePWM;
}ConfigurationLamp;

EEMEM ConfigurationLamp E_ConfigLamp[CONFIG_CNT];
ConfigurationLamp ConfigLamp[CONFIG_CNT];


Походу создано на самом деле 5 копий а не 6 судя по тому что в епроме 10 bytes только занято а не 12.

Добавлено after 7 minutes 31 second:
и для инициализации ConfigLamp и E_ConfigLamp (стартовыми значениями )
Как я понял придется прогнать вот такой цикл ?
for (int i = 0; i< 5; i++)
{
ConfigLamp[i].FlagPower=0;
ConfigLamp[i].ValuePWM=0;
}

Re: EEPROM запись в цикле.

Пт окт 20, 2017 09:12:20

количество человек считает с 1, поэтому если у вас 6 конфигураций, и в программе надо 6 указывать. а вот НОМЕР конфигурации будет на 1 меньше :)
первый будет 0, а последний - 5.

что касается инициализации, то есть несколько способов.
1. если все нулями - есть 2 способа:
1.1 прямо в описании массива в EEPROM выполнить его инициализацию = {0}; а потом прошить в МК полученный .eep файл
1.2 глобальный массив в ОЗУ будет автоматически заполнен нулями, и поэтому достаточно его записать в EEPROM
2. если не все нулями, то можно поступить почти как в п.1: или инициализировать вручную и прошить, или аналогично заполнить в ОЗУ и сохранить.

для заполнения области памяти одинаковыми байтами рекомендую применять функцию memset из модуля string.h
для копирования одной области памяти в другую (например, заполнение массива структур одинаковыми, но ненулевыми, структурами) рекомендую применять функцию memcpy или memmove оттуда же.

Re: EEPROM запись в цикле.

Пт окт 20, 2017 09:32:21

Заполняю структуру для теста вот таки кодом:

Код:
#define CONFIG_CNT 6
typedef struct
{
   char FlagPower;
   char ValuePWM;
}ConfigurationLamp;

EEMEM ConfigurationLamp E_ConfigLamp[CONFIG_CNT];
ConfigurationLamp ConfigLamp[CONFIG_CNT];

for (unsigned char ValueCount = 0; ValueCount < 5; ValueCount++)
{
   ConfigLamp[ValueCount].FlagPower=(ValueCount+1);
   ConfigLamp[ValueCount].ValuePWM=(6-ValueCount);
}
eeprom_update_block((void*)ConfigLamp, (void*)E_ConfigLamp, sizeof(ConfigLamp));



Смотрю заполнение в протеусе:
Изображение


оно же явно не правильное в конце:
000a должно быть = 06
000bдолжно быть = 05

Добавлено after 5 minutes 39 seconds:
Тфу сам тупил )))
Надо же for (unsigned char ValueCount = 0; ValueCount <= 5; ValueCount++).. Чет запарился походу я с этим епромом.

Re: EEPROM запись в цикле.

Пт окт 20, 2017 09:45:44

вы попадает в ловушку неоднообразия... у вас в коде смешано два стиля: нехороший и хороший. я, конечно, рекомендую придерживаться хорошего стиля, а он однозначно требует исключить "магические числа" из кода. и вместе с ними пропадут ошибки.

в чем ваша беда? в том, что вы думаете, будто ValueCount у вас пробегает по ВСЕМ элементам массива... а он, зараза, не пробегает.

вот так ПРАВИЛЬНО делать цикл по ВСЕМ элементам массива:
Код:
for (unsigned char ValueCount = 0; ValueCount < CONFIG_CNT; ValueCount++)
и, разумеется, если вы где-то еще по коду используете КОЛИЧЕСТВО КОНФИГУРАЦИЙ, вместо числа 6 вы ОБЯЗАНЫ использовать константу CONFIG_CNT, иначе зачем вы вообще её вводили?!

Добавлено after 2 minutes 43 seconds:
кстати, пользуйтесь типами строгой размерности. вместо длинного unsigned char применяйте короткий (и однозначный) uint8_t. ну и соответственно для других случаев аналогично in8_t, uint16_t, int16_t и т.д. (где u в начале означает "без знака", а число перед _t - количество бит в переменной).

Re: EEPROM запись в цикле.

Пт окт 20, 2017 11:54:11

Сделал пару функций для теста вроде работают(в протеусе значения меняются) но при перезапуске протеуса все значение в еппром = 00. Грешу на file.BIN созданный мной для еппрома.
Код:
#define CONFIG_AMOUNT 6
typedef struct
{
   char FlagPower;
   char ValuePWM;
}ConfigurationLamp;

EEMEM ConfigurationLamp E_ConfigLamp[CONFIG_AMOUNT];
ConfigurationLamp ConfigLamp[CONFIG_AMOUNT];

unsigned char ValuePWM[CONFIG_AMOUNT];
unsigned char FlagPower[CONFIG_AMOUNT];
void LoadingEEPROM()
{
   eeprom_read_block((void*)E_ConfigLamp, (void*)ConfigLamp, sizeof(ConfigLamp));
   for (unsigned char ValueCount = 0; ValueCount < CONFIG_AMOUNT; ValueCount++)
   {
      FlagPower[ValueCount]=ConfigLamp[ValueCount].FlagPower;
      ValuePWM[ValueCount]=ConfigLamp[ValueCount].ValuePWM;
   }
}

void SaveEEPROM()
{
   for (unsigned char ValueCount = 0; ValueCount < CONFIG_AMOUNT; ValueCount++)
   {
      ConfigLamp[ValueCount].FlagPower=(FlagPower[ValueCount]);
      ConfigLamp[ValueCount].ValuePWM=(ValuePWM[ValueCount]);
   }
   eeprom_update_block((void*)ConfigLamp, (void*)E_ConfigLamp, sizeof(ConfigLamp));
}

int main(void)
{
   LoadingEEPROM();
   init_io();
   init_int0();
   BtnInit();
   init_pwm();
   _delay_ms(10);
   sei();
    while(1)
    {
      SaveEEPROM();
      BtnUpdate();
   }
   return 0;
}


Добавлено after 13 minutes 29 seconds:
походу у функции чтения др порядок.
eeprom_read_block((void*)ConfigLamp, (void*)E_ConfigLamp, sizeof(ConfigLamp));
Куда.
Откуда.
Размер.

Добавлено after 1 hour 13 minutes 18 seconds:
А есть идеи как можно сделать покомпактней функцию UpdateValue();
Спойлер
Код:
 #define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
//----------///init_pwm///----------//
void init_pwm()
{
   TCCR0A=(1<<COM0A1) | (0<<COM0A0) | (1<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | (1<<WGM00);
   TCCR0B=(0<<WGM02) | (0<<CS02) | (1<<CS01) | (0<<CS00);
   OCR0A=0x00;
   OCR0B=0x00;

   TCCR1A=(1<<COM1A1) | (0<<COM1A0) | (1<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (1<<WGM10);
   TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (1<<CS11) | (0<<CS10);
   OCR1AL=0x00;
   OCR1BL=0x00;

   TCCR2A=(1<<COM2A1) | (0<<COM2A0) | (1<<COM2B1) | (0<<COM2B0) | (1<<WGM21) | (1<<WGM20);
   TCCR2B=(0<<WGM22) | (0<<CS22) | (1<<CS21) | (0<<CS20);
   OCR2A=0x00;
   OCR2B=0x00;
}
//----------//
void init_int0()
{
   //настраиваем на срабатывание INT0 по переднему фронту
   EICRA |= (1<<ISC01)|(0<<ISC00);
   //разрешаем внешнее прерывание INT0
   EIMSK |= (1<<INT0);
}
//----------//
void init_io()
{
   DDRB=(0<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)|(0<<PB5)|(0<<PB6)|(0<<PB7);
   PORTB=0x00;
   DDRC=(1<<PC0)|(1<<PC1)|(1<<PC2)|(1<<PC3)|(1<<PC4)|(1<<PC5)|(1<<PC6);
   PORTC=0x00;
   DDRD=(1<<PD0)|(1<<PD1)|(1<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
   PORTD=0x00;
}
//----------//
//настройка параметров работы функций
#define BTN_LOCK_TIME      30               /*время обработки дребезга в милисекундах (10-100)*/
#define BTN_LONG_TIME      1000            /*время фиксации длинного нажатия в милисекундах (1000 - 2500)*/
//настройки портов
/*порт чтения кнопок*/
#define BTN_PORT         PORTB
#define BTN_DDR            DDRB
#define BTN_PIN            PINB
/*пины чтения кнопок*/
#define BTN_LINE_UP      (1<<7)
#define BTN_LINE_DN      (1<<6)
#define BTN_LINE_POWER   (1<<5)
#define BTN_LINE_SW      (1<<0)
//глобальные переменные
volatile uint8_t BtnFlags;               //байт флагов нажатия кнопки
#define BTN_SHRT_UP         (1<<0)         /*бит короткого нажатия кнопки up*/
#define BTN_SHRT_DN         (1<<1)         /*бит короткого нажатия кнопки dn*/
#define BTN_SHRT_POWER      (1<<2)         /*бит короткого нажатия кнопки POWER */
#define BTN_SHRT_SW         (1<<3)         /*бит короткого нажатия кнопки SW*/
#define BTN_LONG_UP         (1<<4)         /*бит длинного нажатия кнопки up*/
#define BTN_LONG_DN         (1<<5)         /*бит длинного нажатия кнопки dn*/
#define BTN_LONG_SW         (1<<6)         /*бит короткого нажатия кнопки SW*/
//----------
//Функция настройки библиотеки работы с кнопками
void BtnInit (void)
{
   BTN_DDR &= ~(BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_POWER|BTN_LINE_SW);//на ввод
   BTN_PORT |= (BTN_LINE_UP| BTN_LINE_DN| BTN_LINE_POWER|BTN_LINE_SW);//подтяжка вкл
}
//----------
//Функция чтения данных о нажатии кнопок
char BtnGet (void)
{
   cli();
   char temp = BtnFlags;
   BtnFlags = 0;
   sei();
   return temp;
}
//----------
//ФУНКЦИЯ ОБРАБОТКИ НАЖАТИЙ КЛАВИШ (вызывать в прерывании с частотой 100 Гц)
//короткое нажатие устанавливает бит BTN_SHRT_X глобальной переменной BtnFlags
//длинное нажатие устанавливает бит BTN_LONG_X глобальной переменной BtnFlags
void BtnExe (void)
{
   static unsigned char BtnLockBit;            //защелка (защита от дребезга)
   static unsigned char BtnLockCoun;         //счетчик защелки (защита от дребезга)
   static unsigned char BtnLongCoun;         //счетчик длинного нажатия
   static unsigned char BtnLastState;         //последнее состояние кнопок перед отпусканием

   char mask = 0;
   if (! (BTN_PIN & BTN_LINE_UP))      mask = BTN_SHRT_UP;
   if (! (BTN_PIN & BTN_LINE_DN))      mask = BTN_SHRT_DN;
   if (! (BTN_PIN & BTN_LINE_POWER))   mask = BTN_SHRT_POWER;
   if (! (BTN_PIN & BTN_LINE_SW))      mask = BTN_SHRT_SW;

   if (mask){                           //опрос состояния кнопки
      if (BtnLockCoun < (BTN_LOCK_TIME/10)){   //клавиша нажата
         BtnLockCoun++;
         return;                        //защелка еще не дощитала - возврат
      }
      BtnLastState = mask;
      BtnLockBit =1;                     //нажатие зафиксировано
      if (BtnLongCoun >= (BTN_LONG_TIME/10))
      return;                        //возврат, т.к. счетчик длинн нажат досчитал до максимума еще раньше
      if (++BtnLongCoun >= (BTN_LONG_TIME/10))
      BtnFlags |= (BtnLastState<<4);         //счетчик досчитал до максимума - устанавливаем биты длинного нажатия
   }
   else{                              //клавиша отжата
      if (BtnLockCoun){
         BtnLockCoun --;
         return;                        //защелка еще не обнулилась - возврат
      }
      if (! BtnLockBit)                  //СТАТИЧЕСКИЙ ВОЗВРАТ
      return;
      BtnLockBit =0;                     //отжатие зафиксировано
      if (BtnLongCoun < (BTN_LONG_TIME/10))
      BtnFlags |= BtnLastState;         //установка бита короткого нажатия
      BtnLongCoun = 0;               //сброс счетчика длительности нажатия
   }
}
//----------****7SEG****----------
#define SEGA 6
#define SEGB 5
#define SEGC 1
#define SEGD 2
#define SEGE 3
#define SEGF 4
#define SEGG 0

#define ANOD1 4
#define ANOD2 7
#define ANOD3 4
//----------
void segchar (unsigned char seg)
{
   switch (seg)
   {
      case 0:
      PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(1<<SEGG);break;
      case 1:
      PORTC=(1<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break;
      case 2:
      PORTC=(0<<SEGA)|(0<<SEGB)|(1<<SEGC)|(0<<SEGD)|(0<<SEGE)|(1<<SEGF)|(0<<SEGG);break;
      case 3:
      PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(1<<SEGF)|(0<<SEGG);break;
      case 4:
      PORTC=(1<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break;
      case 5:
      PORTC=(0<<SEGA)|(1<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break;
      case 6:
      PORTC=(0<<SEGA)|(1<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(0<<SEGG);break;
      case 7:
      PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break;
      case 8:
      PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(0<<SEGE)|(0<<SEGF)|(0<<SEGG);break;
      case 9:
      PORTC=(0<<SEGA)|(0<<SEGB)|(0<<SEGC)|(0<<SEGD)|(1<<SEGE)|(0<<SEGF)|(0<<SEGG);break;
      case 99: //OFF Все сегменты
      PORTC=(1<<SEGA)|(1<<SEGB)|(1<<SEGC)|(1<<SEGD)|(1<<SEGE)|(1<<SEGF)|(1<<SEGG);break;
   }
}

#define CONFIG_AMOUNT 6
typedef struct
{
   char FlagPower;
   char ValuePWM;
}ConfigurationLamp;

EEMEM ConfigurationLamp E_ConfigLamp[CONFIG_AMOUNT];
ConfigurationLamp ConfigLamp[CONFIG_AMOUNT];

unsigned char ValuePWM[CONFIG_AMOUNT];
unsigned char FlagPower[CONFIG_AMOUNT];

//----------

void LoadingEEPROM()
{
   eeprom_read_block((void*)ConfigLamp, (void*)E_ConfigLamp, sizeof(ConfigLamp));
   for (unsigned char ValueCount = 0; ValueCount < CONFIG_AMOUNT; ValueCount++)
   {
      FlagPower[ValueCount]=ConfigLamp[ValueCount].FlagPower;
      ValuePWM[ValueCount]=ConfigLamp[ValueCount].ValuePWM;
   }
}

void SaveEEPROM()
{
   for (unsigned char ValueCount = 0; ValueCount < CONFIG_AMOUNT; ValueCount++)
   {
      ConfigLamp[ValueCount].FlagPower=(FlagPower[ValueCount]);
      ConfigLamp[ValueCount].ValuePWM=(ValuePWM[ValueCount]);
   }
   eeprom_update_block((void*)ConfigLamp, (void*)E_ConfigLamp, sizeof(ConfigLamp));
}
//----------

void UpdateFlagPower(unsigned char ZoneNumber,unsigned char Flag)
{
   FlagPower[ZoneNumber]=Flag;
}

void UpdateValue(void)
{
   for (unsigned char ValueCount = 0; ValueCount < CONFIG_AMOUNT; ValueCount++)
   {
      switch (ValueCount)
      {
         case 0:
         if (FlagPower[ValueCount]==1)
         {
            OCR0A=ValuePWM[ValueCount]*2.56;
         }
         else{
         OCR0A=0;
         }break;
         case 1:
         if (FlagPower[ValueCount]==1)
         {
            OCR0B=ValuePWM[ValueCount]*2.56;
         }
         else{
            OCR0B=0;}break;         
         case 2:
         if (FlagPower[ValueCount]==1)
         {
            OCR1AL=ValuePWM[ValueCount]*2.56;
         }
         else{
         OCR1AL=0;
         }break;         
         case 3:
         if (FlagPower[ValueCount]==1)
         {
            OCR1BL=ValuePWM[ValueCount]*2.56;
         }
         else{
         OCR1BL=0;
         }break;         
         case 4:
         if (FlagPower[ValueCount]==1)
         {
            OCR2A=ValuePWM[ValueCount]*2.56;
         }
         else{
         OCR2A=0;
         }break;         
         case 5:
         if (FlagPower[ValueCount]==1)
         {
            OCR2B=ValuePWM[ValueCount]*2.56;
         }
         else{
         OCR2B=0;
         }break;
      }
   }
}
unsigned char data1 = 0;
unsigned char data2 = 0;
unsigned char count = 0;
unsigned char ZoneNumber=0;

void WriteSeg(unsigned char Number)
{
   data1=ValuePWM[Number]%10;
   data2=ValuePWM[Number]/10;
   PORTB |=(1<<ANOD1);
   PORTD |=(1<<ANOD2);
   PORTD |=(1<<ANOD3);
   segchar(99);
   if(FlagPower[Number]==1)
   {
      count++;
      if (count==1){
         PORTB &= ~(1<<ANOD1);
         segchar(data1);
         PORTD |=(1<<ANOD2);
         PORTD |=(1<<ANOD3);
      }
      if (count==2){
         PORTD &= ~(1<<ANOD2);
         segchar(data2);
         PORTB |=(1<<ANOD1);
         PORTD |=(1<<ANOD3);
      }
      if (count==3){
         PORTD &= ~(1<<ANOD3);
         segchar(Number+1);
         PORTB |=(1<<ANOD1);
         PORTD|=(1<<ANOD2);
      }
      if (count==3){count=0;}
   }
}
ISR(INT0_vect)
{
   WriteSeg(ZoneNumber);
   UpdateValue();
   BtnExe();
}
unsigned char fBtnPower=0;
void BtnUpdate(void)
{
   char BtnMask = BtnGet ();
   if (BtnMask == BTN_SHRT_POWER)
   {
      FlagPower[ZoneNumber]++;
      if (FlagPower[ZoneNumber]>1)
      {
         FlagPower[ZoneNumber]=0;
      }
      SaveEEPROM();
   }
   if ((BtnMask == BTN_SHRT_SW))
   {
      ZoneNumber++;
      if (ZoneNumber==6)
      {
         ZoneNumber=0;
      }
   }
   //одиночное нажатие +
   if ((BtnMask == BTN_SHRT_UP)& (ValuePWM[ZoneNumber] < 99))
   {
      ValuePWM[ZoneNumber]++;
      SaveEEPROM();
   }
   //одиночное нажатие -
   if ((BtnMask == BTN_SHRT_DN)& (ValuePWM[ZoneNumber] > 0))
   {
      ValuePWM[ZoneNumber]--;
      SaveEEPROM();
   }
   //Удержание +
   if ((BtnMask == BTN_LONG_UP) & (ValuePWM[ZoneNumber] < 99))
   {
      while ((!(PINB&0b10000000))& (ValuePWM[ZoneNumber] < 99))
      {
         ValuePWM[ZoneNumber]++;
         _delay_ms(50);
      }
      SaveEEPROM();
   }
   //Удержание -
   if ((BtnMask == BTN_LONG_DN) & (ValuePWM[ZoneNumber] > 0))
   {
      while ((!(PINB&0b01000000))& (ValuePWM[ZoneNumber] > 0))
      {
         ValuePWM[ZoneNumber]--;
         _delay_ms(50);
      }
      SaveEEPROM();
   }
}

int main(void)
{
   LoadingEEPROM();
   _delay_ms(50);
   init_io();
   init_int0();
   BtnInit();
   init_pwm();
   _delay_ms(10);
   sei();
    while(1)
    {
      BtnUpdate();
   }
   return 0;
}

Re: EEPROM запись в цикле.

Пт окт 20, 2017 12:27:09

а объясните: зачем вам отдельные массивы ValuePower и FlagPower, если все то же самое у вас хранится в ConfigLamp? двойной расход памяти, лишние действия по переносу данных туда-сюда... зачем все это?

7seg писал(а):А есть идеи как можно сделать покомпактней функцию UpdateValue();
а что она делает? можете словами описать, потому что анализировать ваш код у меня лично желания нет...

Re: EEPROM запись в цикле.

Пт окт 20, 2017 12:32:49

7seg писал(а):А есть идеи как можно сделать покомпактней функцию UpdateValue();

У Вас там куча повторяющегося кода, который можно вынести из switch-case. Да и switch-case там скорее всего вообще не нужен.

Re: EEPROM запись в цикле.

Пт окт 20, 2017 14:23:22

Функция UpdateValu() обновляет значения OCRХХ ,также проверяет FlagPower который отвечает за состояние канала (включен/выключен).
Так же сюда предполагал добавить плавное включение , т.е при переходе из состояние OFF в ОN повышать значение OCRХХ до значения записанного в еппром, антологичные действия при подачи питания на МК ( так сказать плавное включение ).

Re: EEPROM запись в цикле.

Пт окт 20, 2017 14:29:58

ну, плавное включение явно делать придется по таймеру... наверное.

а что касается остального, то, как я понимаю, функция смотрит флаг и, если он стоит, заносит в соответствующий регистр соответствующее значение, а если флаг сброшен, то заносит туда 0 - верно?

ну так я посоветую в структуру вышеопределенную добавить адрес регистра, который надо обновлять, и в вашей функции пробегать в цикле по всем структурам массива и обновлять по этому правилу содержимое регистра... элементарно! :)

Re: EEPROM запись в цикле.

Пт окт 20, 2017 14:34:35

А насчет массивов ValuePower и FlagPower еще не успел переписать под структуру ConfigLamp которая находиться в ОЗУ.
В AtmelStudio вроде можно писать на с++,меня просто отговорили от использования синтаксиса плюсов в мк из за его реализации, если мк все-таки поддерживает парадигму ооп программирования то это все упрощает . можно создать класс и наполнить его методами(но я\ не уверен что МК AVR полноценно поддерживает с++.)

Re: EEPROM запись в цикле.

Пт окт 20, 2017 14:41:18

С++ поддерживает компилятор, а не МК.
avr-gcc поддерживает.

но я бы вам советовал так глубоко не копать - разберитесь с тем, что уже накопали :)))

Re: EEPROM запись в цикле.

Пт окт 20, 2017 14:53:47

На самом деле с плюсами бы было работать проще и привычней . ) но даже не знаю какой стандарт поддерживает avr-gcc в atmelstudio ведь не так давно вышел очередной стандарт с++17 который пришелся сне с разу по душе в другом моем хобби.
А по этой прошивке походу надо с начало адаптировать код к структуре и повыкидывать лишнее.
Ответить