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

Ошибка при обращении к битовому полю.

Чт сен 27, 2018 09:37:51

Есть массив структур ConfigLamp[CONFIG_AMOUNT].
Обращаюсь у нему следующим образом:
Код:
ConfigLamp[0].ValuePWM=123;
ConfigLamp[0].Flag.Bits.B0=1;

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

В чем может быть проблема может кто подсказать ? был бы признателен.

Ниже код объявления массива и структур:
Код:
//Структура объеденения битовых полей.
struct UnionsBits
{
   unsigned B0:1;
   unsigned B1:1;
   unsigned B2:1;
   unsigned B3:1;
   unsigned B4:1;
   unsigned B5:1;
   unsigned B6:1;
   unsigned B7:1;
};
union Byte
{
   uint8_t Byte;
   struct UnionsBits Bits;
};
#define CONFIG_AMOUNT 1
//Определения нвого типа.
typedef struct {
   uint8_t ValuePWM;
   union Byte Flag;
}Config;

Config ConfigLamp[CONFIG_AMOUNT]; //Массив структур.

Re: Ошибка при обращении к битовому полю.

Чт сен 27, 2018 10:05:50

Да вроде что просили, то и получили. Ничего не должно тереться.
Код:
//   31   ConfigLamp[0].ValuePWM=123;
        LDI     R16, 123
        STS     ConfigLamp, R16
//   32   ConfigLamp[0].Flag.Bits.B0=1;
        LDI     R30, LOW(ConfigLamp)
        LDI     R31, (ConfigLamp) >> 8
        LDD     R16, Z+1
        ORI     R16, 0x01
        STD     Z+1, R16

Только зачем UnionsBits 16-битная?

Re: Ошибка при обращении к битовому полю.

Чт сен 27, 2018 10:12:34

А с чего вы взяли что UnionsBits 16-битная? просто не понимаю асемблер.

Она должна быть 8 бит. т.к состоит из 8 полей B0..B7.

Добавлено after 1 minute 54 seconds:
тут 16ти битная только ConfigLamp

т.к состоит из 2ух 8мибитных.

typedef struct {
uint8_t ValuePWM;
union Byte Flag;
}Config;

Re: Ошибка при обращении к битовому полю.

Чт сен 27, 2018 10:16:45

Потому что в AVR тип unsigned 16-битный.

PS: И не надо второй раз писать union и struct. Вы и так определили тип Byte как union, а UnionsBits как struct.

Код:
//   36   return sizeof(Config);
        LDI     R16, 3
        LDI     R17, 0
        RET


Если вместо unsigned поставить uint8_t, то будет как и задумано
Код:
//   36   return sizeof(Config);
        LDI     R16, 2
        LDI     R17, 0
        RET

Re: Ошибка при обращении к битовому полю.

Чт сен 27, 2018 10:27:23

Понял о чем вы изменил структуру:
//Структура объеденения битовых полей.
Код:
struct UnionsBits
{
   uint8_t B0:1;
   uint8_t B1:1;
   uint8_t B2:1;
   uint8_t B3:1;
   uint8_t B4:1;
   uint8_t B5:1;
   uint8_t B6:1;
   uint8_t B7:1;
};

Re: Ошибка при обращении к битовому полю.

Чт сен 27, 2018 10:28:04

а еще в GCC есть безымянные структуры и юнионы
Код:
typedef union{
   struct{
      uint8_t bit0 : 1;
      uint8_t bit1 : 1;
      uint8_t bit2 : 1;
      uint8_t bit3 : 1;
      uint8_t bit4 : 1;
      uint8_t bit5 : 1;
      uint8_t bit6 : 1;
      uint8_t bit7 : 1;
   };
   uint8_t byte;
} my_data;

my_data d;

d.byte = 0xFF;
d.bit5 = 0;
количество точек при обращении можно уменьшить :)))

Re: Ошибка при обращении к битовому полю.

Чт сен 27, 2018 10:40:44

Только это не помогает (.
Скрины :

Изображение Изображение Изображение Изображение Изображение hunger games 1 plot

Добавлено after 6 minutes 52 seconds:
То есть с данной структурой взаимодействует всего 2 строчки в теле программы. и не могу понят от куда в нее сыпется весь остальной шлак.

Re: Ошибка при обращении к битовому полю.

Чт сен 27, 2018 10:50:05

Даже разбираться не хочу в том бреде что в TWI_SendData(). Это она гадит тебе по памяти.

Re: Ошибка при обращении к битовому полю.

Чт сен 27, 2018 10:56:55

TWI_SendData() не виновата , я ее исключал из цикла.

Добавлено after 2 minutes:
Упс извиняюсь походу это она все таки.

Re: Ошибка при обращении к битовому полю.

Чт окт 04, 2018 04:58:23

Наконец то выдалось свободное время допилить код. 8)
Т.к сам долго провозился с некоторыми моментами, решил поделиться полной наработкой тут может кому и пригодится :)

Реализация драйвера LCD экрана с управлением по протоколу I2C на AtMega8.
Реализация 6-ти управляемых PWM каналов с последующей передачей информации на LCD экран. на AtMega88.

Мастер AtMega88
Спойлер
Код:
#define F_CPU 16000000UL
 
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <stdint.h>
#include <util/twi.h>
#include <string.h>
//==================
#define SET_BIT(port,bit)   port|=(1<<bit)
#define CLEAR_BIT(port,bit) port&= ~(1<<bit)
#define INV_BIT(port,bit)   port ^=(1<<bit)
//==================
//настройка параметров работы функций
#define BTN_LOCK_TIME      20               /*время обработки дребезга в милисекундах (10-100)*/
#define BTN_LONG_TIME      1000            /*время фиксации длинного нажатия в милисекундах (1000 - 2500)*/
//настройки портов
/*порт чтения кнопок*/
#define BTN_PORT1         PORTD
#define BTN_DDR1         DDRD
#define BTN_PIN1         PIND

#define BTN_PORT2         PORTB
#define BTN_DDR2         DDRB
#define BTN_PIN2         PINB
/*пины чтения кнопок*/
#define BTN_LINE_UP         (1<<7)
#define BTN_LINE_DN         (1<<4)
#define BTN_LINE_POWER      (1<<2)
#define BTN_LINE_SW_UP      (1<<4)
#define BTN_LINE_SW_DN      (1<<5)
//глобальные переменные
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_UP      (1<<3)         /*бит короткого нажатия кнопки SW*/
#define BTN_SHRT_SW_DN      (1<<4)         /*бит короткого нажатия кнопки SW*/

#define BTN_LONG_UP         (1<<5)         /*бит длинного нажатия кнопки up*/
#define BTN_LONG_DN         (1<<6)         /*бит длинного нажатия кнопки dn*/
//#define BTN_LONG_PW         (1<<7)         /*бит короткого нажатия кнопки SW*/
//==================
#define ADR_SLAVE               0x30 // i2c адрес драйвера LCD
/*размер буфера TWI модуля*/
#define TWI_BUFFER_SIZE            13   //   
//****************************************************************************
/*Общие статусные коды */                   
#define TWI_START                  0x08  // состояние START сформировано
#define TWI_REP_START              0x10  // состояние повторный START сформировано
#define TWI_ARB_LOST               0x38  // был потерян приоритет
/*Статусные коды ведущего передатчика*/               
#define TWI_MTX_ADR_ACK            0x18  // был передан пакет SLA+W и получено подтверждение
#define TWI_MTX_ADR_NACK           0x20  // был передан пает SLA+W и не получено подтверждение
#define TWI_MTX_DATA_ACK           0x28  // был передан байт данных и получено подтверждение 
#define TWI_MTX_DATA_NACK          0x30  // был передан байт данных и не получено подтверждение
/*Статусные коды ведущего приемника*/
#define TWI_MRX_ADR_ACK            0x40  // был передан пакет SLA+R и получено подтвеждение
#define TWI_MRX_ADR_NACK           0x48  // был передан пакет SLA+R и не получено подтверждение
#define TWI_MRX_DATA_ACK           0x50  // байт данных принят и передано подтверждение 
#define TWI_MRX_DATA_NACK          0x58  // был принят байт данных без подтверждения 
/*Другие статусные коды*/
#define TWI_NO_STATE               0xF8  // неопределенное состояние; TWINT = “0”
#define TWI_BUS_ERROR              0x00  // ошибка на шине из-за некоректных состояний СТАРТ или СТОП
/*Пользовательские коды*/
#define TWI_SUCCESS                0xff
/****************************************************************************
  Определения констант
****************************************************************************/
#define TWI_READ_BIT    0       // позиция R/W бита в адресном пакете
#define TWI_ADR_BITS    1       // позиция адреса в адресном пакете
#define TRUE            1
#define FALSE           0
#define TWSR_MASK      0xfc 
//==================
//Структура объеденения битовых полей.
struct UnionsBits
{
   uint8_t B0:1;   // параметр ON\OFF
   uint8_t B1:1;   // Активнный(выбранный) ШИМ. Для Курсора LCD.
   uint8_t B2:1;   // RESERV BIT FLAG
   uint8_t B3:1;   // RESERV BIT FLAG
   uint8_t B4:1;   // RESERV BIT FLAG
   uint8_t B5:1;   // RESERV BIT FLAG
   uint8_t B6:1;   // RESERV BIT FLAG
   uint8_t B7:1;   // RESERV BIT FLAG
};
union Byte
{
   uint8_t Byte;
   struct UnionsBits Bits;
};

//Определения нового типа.
typedef struct {
   uint8_t ValuePWM;   //Значения PWM
   union Byte Flag;   //Праметры записанные в битовых полях
}Config;

#define CONFIG_AMOUNT 6
Config ConfigPWM[CONFIG_AMOUNT]; //Массив структур.
EEMEM Config E_ConfigPWM[CONFIG_AMOUNT];
uint8_t ValuePWM[CONFIG_AMOUNT]={0};

volatile static uint8_t twiBuf[TWI_BUFFER_SIZE];
volatile static uint8_t twiState = TWI_NO_STATE;     
volatile static uint8_t twiMsgSize;
uint8_t BuffTransmitTWI[13]={0};
/*предделители для установки скорости обмена twi модуля*/
uint8_t pre[4] = {2, 8, 32, 128};
/****************************************************************************
 Инициализация и установка частоты SCL сигнала
****************************************************************************/
uint8_t TWI_MasterInit(uint16_t fr)
{
  uint8_t i;
  uint16_t twbrValue;
 
  for(i = 0; i<4; i++){
    twbrValue = ((((F_CPU)/1000UL)/fr)-16)/pre[i];
    if ((twbrValue > 0)&& (twbrValue < 256)){
       TWBR = (uint8_t)twbrValue;
       TWSR = i;
       TWDR = 0xFF;
       TWCR = (1<<TWEN);
       return TWI_SUCCESS;
    }
  }
  return 0; 
}   
/****************************************************************************
 Проверка - не занят ли TWI модуль. Используется внутри модуля
****************************************************************************/
static uint8_t TWI_TransceiverBusy(void)
{
  return (TWCR & (1<<TWIE));                 
}
/****************************************************************************
 Взять статус TWI модуля
****************************************************************************/
uint8_t TWI_GetState(void)
{
  while (TWI_TransceiverBusy());             
  return twiState;                       
}
/****************************************************************************
 Передать сообщение msg из msgSize байтов на TWI шину
****************************************************************************/
void TWI_SendData(uint8_t *msg, volatile uint8_t msgSize)
{
  uint8_t i;

  while(TWI_TransceiverBusy());   //ждем, когда TWI модуль освободится             

  twiMsgSize = msgSize;           //сохряняем кол. байт для передачи             
  twiBuf[0]  = msg[0];            //и первый байт сообщения
 
  if (!(msg[0] & (TRUE<<TWI_READ_BIT)))
  {   //если первый байт типа SLA+W
    for (i = 1; i < msgSize; i++)
   {         //то сохряняем остальную часть сообщения
      twiBuf[i] = msg[i];
    }
  }
                       
  twiState = TWI_NO_STATE ;
  TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA); //разрешаем прерывание и формируем состояние старт                           
}
/****************************************************************************
 Переписать полученные данные в буфер msg в количестве msgSize байт.
****************************************************************************/
uint8_t TWI_GetData(uint8_t *msg, uint8_t msgSize)
{
  uint8_t i;

  while(TWI_TransceiverBusy());    //ждем, когда TWI модуль освободится

  if(twiState == TWI_SUCCESS){     //если сообщение успешно принято,                         
    for(i = 0; i < msgSize; i++){  //то переписываем его из внутреннего буфера в переданный
      msg[i] = twiBuf[i];
    }
  }
 
  return twiState;                                   
}
/****************************************************************************
 Обработчик прерывания TWI модуля
****************************************************************************/
ISR(TWI_vect)
{
  volatile static uint8_t ptr;
  uint8_t stat = TWSR & TWSR_MASK;
 
  switch (stat){
   
    case TWI_START:                   // состояние START сформировано
    case TWI_REP_START:               // состояние повторный START сформировано       
       ptr = 0;     

    case TWI_MTX_ADR_ACK:             // был передан пакет SLA+W и получено подтверждение
    case TWI_MTX_DATA_ACK:            // был передан байт данных и получено подтверждение 
       if (ptr < twiMsgSize){
          TWDR = twiBuf[ptr];                    //загружаем в регистр данных следующий байт
          TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT); //сбрасываем флаг TWINT   
          ptr++;
       }
       else{
          twiState = TWI_SUCCESS; 
          TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTO)|(0<<TWIE); //формируем состояние СТОП, сбрасываем флаг, запрещаем прерывания
       }
       break;
     
    case TWI_MRX_DATA_ACK:          //байт данных принят и передано подтверждение 
       twiBuf[ptr] = TWDR;
       ptr++;
   
    case TWI_MRX_ADR_ACK:           //был передан пакет SLA+R и получено подтвеждение 
      if (ptr < (twiMsgSize-1)){
        TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWEA);  //если это не предпоследний принятый байт, формируем подтверждение                             
      }
      else {
        TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT);            //если приняли предпоследний байт, подтверждение не формируем
      }   
      break;
     
    case TWI_MRX_DATA_NACK:       //был принят байт данных без подтверждения     
      twiBuf[ptr] = TWDR;
      twiState = TWI_SUCCESS; 
      TWCR = (1<<TWEN)|(1<<TWINT)|(1<<TWSTO); //формируем состояние стоп
      break;
     
    case TWI_ARB_LOST:          //был потерян приоритет
      TWCR = (1<<TWEN)|(1<<TWIE)|(1<<TWINT)|(1<<TWSTA); // сбрасываем флаг TWINT, формируем повторный СТАРТ
      break;
     
    case TWI_MTX_ADR_NACK:      // был передан пает SLA+W и не получено подтверждение
    case TWI_MRX_ADR_NACK:      // был передан пакет SLA+R и не получено подтверждение   
    case TWI_MTX_DATA_NACK:     // был передан байт данных и не получено подтверждение
    case TWI_BUS_ERROR:         // ошибка на шине из-за некоректных состояний СТАРТ или СТОП
    default:     
      twiState = stat;                                                                                   
      TWCR = (1<<TWEN)|(0<<TWIE)|(0<<TWINT)|(0<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC); //запретить прерывание                             
  }
}
void WriteDataBuf()
{
   /*Копируем массивы структур ConfigPWM в Массив buf со сдвигом на 1ну ячейку  */
   memcpy(BuffTransmitTWI+1,ConfigPWM,sizeof(BuffTransmitTWI)-1);
}
//----------
void LoadingEEPROM()
{
   eeprom_read_block((void*)ConfigPWM, (void*)E_ConfigPWM, sizeof(ConfigPWM));
   for (uint8_t CountChannel = 0; CountChannel < CONFIG_AMOUNT; CountChannel++)
   {
      ValuePWM[CountChannel]=ConfigPWM[CountChannel].ValuePWM;
      ConfigPWM[CountChannel].ValuePWM=0;
   }
}

void UpdateEEPROM()
{
   eeprom_update_block((void*)ConfigPWM, (void*)E_ConfigPWM, sizeof(ConfigPWM));
}

//----------
void InitIO()
{
   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)|(0<<PD2)|(1<<PD3)|(1<<PD4)|(1<<PD5)|(1<<PD6)|(1<<PD7);
   PORTD=0x00;
}
//----------///init_pwm///----------//
void InitPWM()
{
   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 BtnInit (void)
{
   BTN_DDR1 &= ~(BTN_LINE_UP| BTN_LINE_DN|BTN_LINE_POWER);//на ввод
   BTN_PORT1 |= (BTN_LINE_UP| BTN_LINE_DN|BTN_LINE_POWER);//подтяжка вкл
   BTN_DDR2 &= ~(BTN_LINE_SW_UP|BTN_LINE_SW_DN);//на ввод
   BTN_PORT2 |= (BTN_LINE_SW_UP|BTN_LINE_SW_DN);//подтяжка вкл
}
//----------
//Функция чтения данных о нажатии кнопок
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_PIN1 & BTN_LINE_UP))      mask = BTN_SHRT_UP;
   if (! (BTN_PIN1 & BTN_LINE_DN))      mask = BTN_SHRT_DN;
   if (! (BTN_PIN1 & BTN_LINE_POWER))   mask = BTN_SHRT_POWER;
   if (! (BTN_PIN2 & BTN_LINE_SW_UP))   mask = BTN_SHRT_SW_UP;
   if (! (BTN_PIN2 & BTN_LINE_SW_DN))   mask = BTN_SHRT_SW_DN;

   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<<5);         //счетчик досчитал до максимума - устанавливаем биты длинного нажатия
   }
   else{                              //клавиша отжата
      if (BtnLockCoun){
         BtnLockCoun --;
         return;                        //защелка еще не обнулилась - возврат
      }
      if (! BtnLockBit)                  //СТАТИЧЕСКИЙ ВОЗВРАТ
      return;
      BtnLockBit =0;                     //отжатие зафиксировано
      if (BtnLongCoun < (BTN_LONG_TIME/10))
      BtnFlags |= BtnLastState;         //установка бита короткого нажатия
      BtnLongCoun = 0;               //сброс счетчика длительности нажатия
   }
}
void CursorCLR()
{
   ConfigPWM[0].Flag.Bits.B1=0;
   ConfigPWM[1].Flag.Bits.B1=0;
   ConfigPWM[2].Flag.Bits.B1=0;
   ConfigPWM[3].Flag.Bits.B1=0;
   ConfigPWM[4].Flag.Bits.B1=0;
   ConfigPWM[5].Flag.Bits.B1=0;
}
#define MAX_VALUE_CHANNEL 220
uint8_t ActiveHeatingZone=0;
uint8_t FlagLongBT=0;
volatile uint8_t FlagEnableIncrement=0;
uint8_t FlagSmoothStart=1;
void BtnUpdate(void)
{
   char BtnMask = BtnGet ();
   if (BtnMask == BTN_SHRT_POWER)
   {
      INV_BIT(ConfigPWM[ActiveHeatingZone].Flag.Byte,0);
      UpdateEEPROM();
      //Если был переход из OFF в ON
      if(ConfigPWM[ActiveHeatingZone].Flag.Bits.B0==1)
      {
         ValuePWM[ActiveHeatingZone]=ConfigPWM[ActiveHeatingZone].ValuePWM;
         ConfigPWM[ActiveHeatingZone].ValuePWM=0;
         FlagSmoothStart=1;
      }
   }
   //одиночное нажатие +
   if ((BtnMask == BTN_SHRT_UP)&&(ConfigPWM[ActiveHeatingZone].Flag.Bits.B0 == 1))
   {
      if(ConfigPWM[ActiveHeatingZone].ValuePWM<MAX_VALUE_CHANNEL){
         ConfigPWM[ActiveHeatingZone].ValuePWM++;
         UpdateEEPROM();
      }
   }
   //одиночное нажатие -
   if ((BtnMask == BTN_SHRT_DN)&&(ConfigPWM[ActiveHeatingZone].Flag.Bits.B0 == 1))
   {
      if(ConfigPWM[ActiveHeatingZone].ValuePWM){
         ConfigPWM[ActiveHeatingZone].ValuePWM--;
         UpdateEEPROM();
      }
   }
   //длинное нажатие нажатие +
   if ((BtnMask == BTN_LONG_UP)&&(ConfigPWM[ActiveHeatingZone].Flag.Bits.B0 == 1))
   {
      FlagLongBT=1;
   }
   //длинное нажатие нажатие -
   if ((BtnMask == BTN_LONG_DN)&&(ConfigPWM[ActiveHeatingZone].Flag.Bits.B0 == 1))
   {
      FlagLongBT=1;
   }
   if ((BtnMask == BTN_SHRT_SW_UP))
   {
      if(ActiveHeatingZone<5) ActiveHeatingZone++;
      CursorCLR();
      ConfigPWM[ActiveHeatingZone].Flag.Bits.B1=1;
   }
   if ((BtnMask == BTN_SHRT_SW_DN))
   {
      if(ActiveHeatingZone>0) ActiveHeatingZone--;
      CursorCLR();
      ConfigPWM[ActiveHeatingZone].Flag.Bits.B1=1;
   }
}
void UpdlngBt()
{
   if (FlagLongBT)
   {
      if((!(PIND&BTN_LINE_UP))||(!(PIND&BTN_LINE_DN)))
      {
         if(!(PIND&BTN_LINE_UP))
         {
            if ((FlagEnableIncrement)&&(ConfigPWM[ActiveHeatingZone].ValuePWM<MAX_VALUE_CHANNEL))
            {
               ConfigPWM[ActiveHeatingZone].ValuePWM++;
               FlagEnableIncrement=0;
            }
         } 
         if(!(PIND&BTN_LINE_DN))
         {
            if (FlagEnableIncrement)
            {
               if(ConfigPWM[ActiveHeatingZone].ValuePWM){
                  ConfigPWM[ActiveHeatingZone].ValuePWM--;
               }
               FlagEnableIncrement=0;
            }
         }
      }else
      {
         UpdateEEPROM();
         FlagLongBT=0;
      }
   }
}
//Функция записи значения PWM
#define CONST_POWER 1.15
void WriteValuePWM(uint8_t Channel,uint8_t ValuePWM)
{
   switch (Channel)
   {
      case 0:OCR0A=(uint8_t)ValuePWM*CONST_POWER;break;
      case 1:OCR0B=(uint8_t)ValuePWM*CONST_POWER;break;
      case 2:OCR1AL=(uint8_t)ValuePWM*CONST_POWER;break;
      case 3:OCR1BL=(uint8_t)ValuePWM*CONST_POWER;break;
      case 4:OCR2A=(uint8_t)ValuePWM*CONST_POWER;break;
      case 5:OCR2B=(uint8_t)ValuePWM*CONST_POWER;break;
   }
}
//Функция считывания значения PWM
char ReadValue(uint8_t Channel)
{
   static uint8_t ValuePWM=0;
   switch (Channel)
   {
      case 0:ValuePWM=OCR0A;break;
      case 1:ValuePWM=OCR0B;break;
      case 2:ValuePWM=OCR1AL;break;
      case 3:ValuePWM=OCR1BL;break;
      case 4:ValuePWM=OCR2A;break;
      case 5:ValuePWM=OCR2B;break;
   }
   return(ValuePWM/CONST_POWER);
}
/*
Функция обновления значений ШИМ()
{
   For(СчетчикКанала=0;СчетчикКанала < 6;СчетчикКанала++)
   {
      Если(РазрешенПлавныйСтарт)
      {
         Если(Текущие значение[СчетчикКанала] < заданного значения[СчетчикКанала])
         {
            Если(Разрешенно Прибавлять)
            {
               Текущие значение++;
               Если(ФлагПитания Активен)
               {
                  записываем значения в регистр шим.;
               } Иначе запписываем 0 в регистр шим.;
            }
            Запретить прибавлять;
         }
         Если(счетчик == 5)
         {
            Если(Текущие значение[СчетчикКанала] == задонному значению[СчетчикКанала])
            Если(ТекущиеЗНачение[активного канала]==ЗадонномуЗначению[активного канала])
            Обнулить РазрешениеПлавногоСтарта;
         }
      }
      Иначе
      {
         Если(ФлагПитания Активен)
         {
            записываем значения в регистр шим.;
         } Иначе запписываем 0 в регистр шим.;
      }
   }
}
*/
void UpdateValue(void)
{
   for(uint8_t CountChannel=0;CountChannel<CONFIG_AMOUNT;CountChannel++)
   {
      if(FlagSmoothStart)
      {
         if(ConfigPWM[CountChannel].ValuePWM < (ValuePWM[CountChannel]))
         {
            if(FlagEnableIncrement)
            {
               if(ConfigPWM[CountChannel].Flag.Bits.B0 == 1){
                  ConfigPWM[CountChannel].ValuePWM++; //Если включен канал шим, то веддем плавный отсчет
               }else{
                  ConfigPWM[CountChannel].ValuePWM=ValuePWM[CountChannel]; //Иначе просто записывает дданые в ОЗУ.
               }
               if(ConfigPWM[CountChannel].Flag.Bits.B0 == 1)
               {
                  WriteValuePWM(CountChannel,ConfigPWM[CountChannel].ValuePWM);
               }
               else WriteValuePWM(CountChannel,0x00);
            }
            FlagEnableIncrement=0;
         }
         if(CountChannel==5)
         {
            if(ConfigPWM[CountChannel].ValuePWM == ValuePWM[CountChannel])
               if(ConfigPWM[ActiveHeatingZone].ValuePWM == ValuePWM[ActiveHeatingZone])
                  FlagSmoothStart=0;
         }
      }
      else
      {
         if(ConfigPWM[CountChannel].Flag.Bits.B0 == 1)
         {
            WriteValuePWM(CountChannel,ConfigPWM[CountChannel].ValuePWM);
         }
         else WriteValuePWM(CountChannel,0x00);
      }
   }
}
void InitStartVarible()
{
   CursorCLR();
   ConfigPWM[ActiveHeatingZone].Flag.Bits.B1=1;
}
uint8_t CountDIV=7;
uint8_t CountDIV2=2;

int main(void)
{
   BuffTransmitTWI[0] = (ADR_SLAVE<<1);   //Байт определяющий адрес слейва
   TWI_MasterInit(100);               //Иницилизация TWI и установка частоты в kHz
   LoadingEEPROM();
   InitIO();
   InitPWM();
   BtnInit();
   InitStartVarible();
   sei();
   while(1)
   {
      UpdateValue();
      WriteDataBuf();
      TWI_SendData(BuffTransmitTWI,sizeof(BuffTransmitTWI));
      if(!(CountDIV--))
      {
         BtnExe();               //Вызывается раз в 10ms.
         if(!(CountDIV2--))
         {
            FlagEnableIncrement=1;
            CountDIV2=2;
         }
         CountDIV=7;         //Делитель
      }
      BtnUpdate();
      UpdlngBt();
   }
   return 0;
}



Slave Atmega8
Спойлер
Код:
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/twi.h>
#include <avr/interrupt.h>

#define SET_BIT(port,bit)   port|=(1<<bit)
#define CLR_BIT(port,bit)   port&= ~(1<<bit)
#define INV_BIT(port,bit)   port ^=(1<<bit)

#define LCD_DATA_PORT   PORTD
#define LCD_DATA_DDR   DDRD
#define LCD_CMD_PORT   PORTB
#define LCD_CMD_DDR      DDRB
#define CHIP1   0
#define CHIP2   1
#define DI      2
#define RW      3
#define E      4
#define RST      5
#define I2C_ADDR 0x30
uint8_t data1=1;
volatile uint8_t BufferChar[6][3]={0};
//Структура объеденения битовых полей.
struct UnionsBits
{
   uint8_t B0:1;   // параметр ON\OFF
   uint8_t B1:1;   // Активнный(выбранный) ШИМ. Для Курсора LCD.
   uint8_t B2:1;   // RESERV BIT FLAG
   uint8_t B3:1;   // RESERV BIT FLAG
   uint8_t B4:1;   // RESERV BIT FLAG
   uint8_t B5:1;   // RESERV BIT FLAG
   uint8_t B6:1;   // RESERV BIT FLAG
   uint8_t B7:1;   // RESERV BIT FLAG
};
union Byte
{
   uint8_t Byte;
   struct UnionsBits Bits;
};

//Определения нвого типа.
typedef struct {
   union Byte Flag;   //Праметры записанные в битовых полях
}Config;

#define CONFIG_AMOUNT 6
Config ConfigLCD[CONFIG_AMOUNT]; //Массив структур.

#define CHAR_F 10
uint8_t BufRecivDat[12]={0};
PROGMEM const unsigned char FONTNUMBERS[15][32] = {
   //0
   {0x00,0x00,0xE0,0xF0,0x38,0x38,0x38,0x38,
      0x38,0x38,0x38,0x38,0xF0,0xE0,0x00,0xFE,
      0x00,0x00,0x07,0x0F,0x1C,0x1C,0x1C,0x1C,
   0x1C,0x1C,0x1C,0x1C,0x0F,0x07,0x00,0x7F},
   //1
   {0x00,0x00,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
      0xC0,0xC0,0xC0,0xC0,0xF0,0xF0,0x00,0xFE,
      0x00,0x00,0x03,0x07,0x0F,0x1D,0x19,0x01,
   0x01,0x01,0x01,0x01,0x07,0x07,0x00,0x7F},
   //2
   {0x00,0x00,0xE0,0xF0,0x78,0x38,0x78,0xF0,
      0xC0,0x80,0x00,0x00,0xF8,0xF8,0x00,0xFE,
      0x00,0x00,0x03,0x07,0x0E,0x1C,0x00,0x00,
   0x01,0x03,0x07,0x0E,0x1F,0x1F,0x00,0x7F},
   //3
   {0x00,0x00,0xE0,0xF0,0x78,0x38,0x38,0xF0,
      0xF0,0x38,0x38,0x78,0xF0,0xE0,0x00,0xFE,
      0x00,0x00,0x0F,0x1F,0x1C,0x00,0x00,0x07,
   0x07,0x00,0x00,0x1C,0x1F,0x0F,0x00,0x7F},
   //4
   {0x00,0x00,0xE0,0xE0,0xE0,0x60,0x60,0x60,
      0xF8,0xF8,0x60,0x60,0x60,0x60,0x00,0xFE,
      0x00,0x00,0x01,0x03,0x07,0x0E,0x1C,0x18,
   0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x7F},
   //5
   {0x00,0x00,0xF8,0xF8,0x00,0x00,0xC0,0xF0,
      0x78,0x38,0x38,0x70,0xE0,0xC0,0x00,0xFE,
      0x00,0x00,0x1F,0x1F,0x18,0x18,0x1F,0x1F,
   0x00,0x00,0x00,0x00,0x1F,0x1F,0x00,0x7F},
   //6
   {0x00,0x00,0xE0,0xF8,0x38,0x18,0x00,0xE0,
      0xF0,0x38,0x18,0x38,0xF0,0xE0,0x00,0xFE,
      0x00,0x00,0x0F,0x0F,0x1C,0x18,0x18,0x1B,
   0x1F,0x1C,0x18,0x1C,0x0F,0x07,0x00,0x7F},
   //7
   {0x00,0x00,0xF8,0xF8,0x38,0x38,0x38,0x70,
      0xE0,0xC0,0x80,0x00,0x00,0x00,0x00,0xFE,
      0x00,0x00,0x1F,0x1F,0x00,0x00,0x00,0x00,
   0x00,0x01,0x03,0x07,0x0E,0x1C,0x00,0x7F},
   //8
   {0x00,0x00,0xE0,0xF0,0x38,0x18,0x38,0xF0,
      0xF0,0x38,0x18,0x38,0xF0,0xE0,0x00,0xFC,
      0x00,0x00,0x07,0x0F,0x1C,0x18,0x1C,0x0F,
   0x0F,0x1C,0x18,0x1C,0x0F,0x07,0x00,0x7F},
   //9
   {0x00,0x00,0xE0,0xF0,0x38,0x18,0x18,0x38,
      0xF8,0xD8,0x18,0x38,0xF0,0xE0,0x00,0xFE,
      0x00,0x00,0x07,0x0F,0x1C,0x18,0x18,0x1C,
   0x0F,0x03,0x00,0x18,0x1F,0x0F,0x00,0x7F},
   //знак F  для OFF.
   {0x00,0x00,0xF0,0xF0,0x00,0x00,0x00,0xF0,
      0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,
      0x00,0x00,0x07,0x07,0x06,0x06,0x06,0x07,
   0x07,0x06,0x06,0x06,0x0F,0x0F,0x00,0x7F},
   //____СИМВОЛЫ ДЛЯ ФОНА___________________
   //донышко 11
   {0xF0,0xFC,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
      0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
   0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
   //Горловина 12
   {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
      0xFE,0xFE,0xFE,0xFE,0xFC,0xF8,0x80,0x80,
      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
   0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
   //Резьба 13
   {0xFE,0xFE,0x80,0x80,0xF0,0xF0,0x80,0x80,
      0xF0,0xF0,0x80,0x80,0x80,0x80,0x00,0x00,
      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
   0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00},
   //Тело 14
   {0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
      0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,0xFE,
      0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
   0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},
};

void I2C_init(uint8_t address);
void I2C_stop(void);
void I2C_setCallbacks(void (*recv)(uint8_t), void (*req)());

inline void __attribute__((always_inline)) I2C_transmitByte(uint8_t data)
{
   TWDR = data;
}

static void (*I2C_recv)(uint8_t);
static void (*I2C_req)();

void I2C_setCallbacks(void (*recv)(uint8_t), void (*req)())
{
   I2C_recv = recv;
   I2C_req = req;
}

void I2C_init(uint8_t address)
{
   cli();
   // load address into TWI address register
   TWAR = address << 1;
   // set the TWCR to enable address matching and enable TWI, clear TWINT, enable TWI interrupt
   TWCR = (1<<TWIE) | (1<<TWEA) | (1<<TWINT) | (1<<TWEN);
   sei();
}

void I2C_stop(void)
{
   // clear acknowledge and enable bits
   cli();
   TWCR = 0;
   TWAR = 0;
   sei();
}

ISR(TWI_vect)
{
   switch(TW_STATUS)
   {
      case TW_SR_DATA_ACK:
      // received data from master, call the receive callback
      I2C_recv(TWDR);
      TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
      break;
      case TW_ST_SLA_ACK:
      // master is requesting data, call the request callback
      I2C_req();
      TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
      break;
      case TW_ST_DATA_ACK:
      // master is requesting data, call the request callback
      I2C_req();
      TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
      break;
      case TW_BUS_ERROR:
      // some sort of erroneous state, prepare TWI to be readdressed
      TWCR = 0;
      TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
      break;
      default:
      TWCR = (1<<TWIE) | (1<<TWINT) | (1<<TWEA) | (1<<TWEN);
      break;
   }
}
/************************************************************************/
/* Функция отправки команды дисплею. ( lcd_cmd )                     */
/************************************************************************/
void lcd_cmd(unsigned char cmd)
{
   _delay_us(2);
   LCD_DATA_PORT = cmd;
   _delay_us(1);
   SET_BIT(LCD_CMD_PORT,E);
   _delay_us(8);
   CLR_BIT(LCD_CMD_PORT,E);
   _delay_us(2);
}
/************************************************************************/
/* Функция отправки данных дисплею. ( lcd_data )                     */
/************************************************************************/
void lcd_data(unsigned char data,uint8_t FlagInvert)
{
   _delay_us(2);
   LCD_CMD_PORT |= (1<<DI);
   _delay_us(2);
   if(FlagInvert)
   {
         LCD_DATA_PORT = ~data;
   }
   else
   {
         LCD_DATA_PORT = data;
   }
   _delay_us(2);
   LCD_CMD_PORT |= (1<<E);
   _delay_us(8);
   LCD_CMD_PORT &= ~(1<<E);
   _delay_us(2);
   LCD_CMD_PORT &= ~(1<<DI);
   _delay_us(2);
}
/************************************************************************/
/* Функция инициализации дисплея. ( lcd_init )                         */
/************************************************************************/
void lcd_init()
{
   LCD_DATA_DDR = 0xFF;
   LCD_CMD_DDR |= (1<<DI)|(1<<RW)|(1<<E)|(1<<CHIP1)|(1<<CHIP2)|(1<<RST);
   LCD_CMD_PORT |= (1<<RST);
   LCD_CMD_PORT &=~((1<<CHIP2)|(1<<CHIP1));
   LCD_CMD_PORT |= (1<<CHIP1);
   lcd_cmd(0x3F);
   LCD_CMD_PORT &=~((1<<CHIP2)|(1<<CHIP1));
   LCD_CMD_PORT |= (1<<CHIP2);
   lcd_cmd(0x3F);
}
/************************************************************************/
/* Установка курсора на дисплее, ось X. ( set_x )                  */
/************************************************************************/
void set_x(unsigned char pos_x)
{
   LCD_DATA_PORT = pos_x|0xB8;
   _delay_us(2);
   LCD_CMD_PORT |= (1<<E);
   _delay_us(8);
   LCD_CMD_PORT &= ~(1<<E);
   _delay_us(2);
}
/************************************************************************/
/* Установка курсора на дисплее, ось Y.  ( set_y )                  */
/************************************************************************/
void set_y(unsigned char pos_y)
{
   LCD_DATA_PORT = pos_y|0x40;
   _delay_us(2);
   LCD_CMD_PORT |= (1<<E);
   _delay_us(8);
   LCD_CMD_PORT &= ~(1<<E);
   _delay_us(2);
}
void lcd_big_number(uint8_t Chip, uint8_t x, uint8_t y, uint8_t number,uint8_t FlagInvert)
{
   x=x*2;
   y=y*16;
   uint8_t i,col;
   uint16_t addr;
   addr= (uint16_t)number*32;
   if(Chip == 2)
   {
      LCD_CMD_PORT &= ~(1<<CHIP1);
      LCD_CMD_PORT |= (1<<CHIP2);
      col = y;
   }
   else
   {
      LCD_CMD_PORT &= ~(1<<CHIP2);
      LCD_CMD_PORT |= (1<<CHIP1);
      col = y;
   }
   
   set_x(x);
   set_y(col);
   
   for(i=0;i<32;i++,addr++,col++)
   {
      if (i == 16)
      {
         col=y;
         x= x+1;
         set_x(x);
         set_y(col);
      }
      else
      {
         set_y(col);
      }
      lcd_data(pgm_read_byte((uint16_t)FONTNUMBERS+addr),FlagInvert);
   }
}
void RenderBackGround()
{
   lcd_big_number(1,3,1,11,0);
   lcd_big_number(1,3,2,14,0);
   lcd_big_number(1,3,3,14,0);
   lcd_big_number(2,3,0,14,0);
   lcd_big_number(2,3,1,14,0);
   lcd_big_number(2,3,2,12,0);
   lcd_big_number(2,3,3,13,0);
}
void FillBuffer()
{
   uint8_t Value[6];
   for (uint8_t tX = 0; tX < 6; tX++ )
   {
      /*Достаем кажддое второе число из массива получееного
      по и2с , для дальнейшего преобразования в три символа.*/
      Value[tX]=BufRecivDat[tX*2];
      //Параметры из буфера
      ConfigLCD[tX].Flag.Byte=BufRecivDat[tX*2+1];
   }
   for (uint8_t tX = 0; tX < 6; tX++ )
   {
      uint8_t TempResult=0;
      for (uint8_t i = 0; i < 3; i++)
      {
         TempResult   =Value[tX] % 10;
         Value[tX]   =Value[tX] / 10;
         /*Записываем результат преобразования
         разбитя числа в буффер вывода на экран */
         if (ConfigLCD[tX].Flag.Bits.B0){
            BufferChar[tX][i]   =TempResult;
         }else{
            BufferChar[tX][i]=CHAR_F;
            BufferChar[tX][2]=0;
         }
      }
   }
}
void UpdateLCD()
{
   for (uint8_t tX = 0; tX < 6 ; tX++ )
   {
      for (uint8_t tY = 0; tY < 3; tY++ )
      {
         if(tX<3)
            //Выводим символы на первый чип
            lcd_big_number(1,tY,tX+1,BufferChar[tX][tY],ConfigLCD[tX].Flag.Bits.B1);
         else
            ////Выводим символы на второй чип
            lcd_big_number(2,tY,tX-3,BufferChar[tX][tY],ConfigLCD[tX].Flag.Bits.B1);
      }
   }
}
uint8_t BufCount=0;
void I2C_received(uint8_t received_data)
{
   if (BufCount < 12)
   {
      BufRecivDat[BufCount] = received_data;
      BufCount++;
      if(BufCount >= 12) BufCount=0;
   }
}
void I2C_requested()
{
   I2C_transmitByte(data1);
}

void setup()
{
   // set received/requested callbacks
   I2C_setCallbacks(I2C_received, I2C_requested);

   // init I2C
   I2C_init(I2C_ADDR);
}
void avr_init()
{
   DDRC = 0x00;
   sei();
}
int main(void)
{
   avr_init();
   lcd_init();
   lcd_cmd(0xC0);
   setup();
   RenderBackGround();
   sei();
   while(1)
   {
      FillBuffer();
      UpdateLCD();
   }
   return 0;
}


Схема:
СпойлерИзображение


Картинка:

Изображение

Добавлено after 7 minutes 9 seconds:
А сам Теперь буду думать как сюда прикрутить внешний протокол ModBus ))

Предчувствуя следующий объем кода походу придется добавлять еще один МК с двумя уартами 1 для связи с Мастером AtMega88 2ой уже выход ModBus.
Хотя это только предположения.
Но на данный момент как я думаю вычислительные ресурсы двух мк исчерпаны. (

Добавлено after 31 minute 24 seconds:
Просьба к модераторам данного форума. Если имеется возможность изменить название темы для более детального понимания ее содержания.
Тема: Реализация 6-ти PWM каналов с передачей информации по I2C на LCD Драйвер.

Re: Ошибка LCD

Ср окт 10, 2018 07:53:05

Собрал это дело в железе и столкнулся с интересной проблемой один из чипов экрана после кратковременного отключения(1-10 сек) при повторном включении не выводит изображение(информацию). кто нибудь сталкивался с подобным ?
ВещДоки :)
Изображение
Изображение
Изображение

Добавлено after 2 minutes 19 seconds:
Re: Ошибка при обращении к битовому полю.
Плата грязновата , но для прототипа думаю это не страшно XD
Ответить