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

Ошибки В i2c обмен Atmega88 -> Atmega8

Вт сен 11, 2018 09:34:21

К отданному из проектов решил прикрутить LCD экран МТ12864 на чипе (KS0108).
проблем огребся по самое не хочу т.к его нужно было повернуть на 90 градусов и подключить уже к готовому устройству.
Решением было сделать драйвер для этого экрана на AtMega8 и принимать данные по i2c.
Разобравшись с подключением ,кодировкой , встал вопрос о шине данных как мне казалось я его заставил работать.
Мастер был АтМега88 , слейв Atmega8.
И все вроде-бы работает, пока не добавляю обработчик прерываний на AtMega8.
В чем проблемма не могу понять (.
Но выглядит она след образом:
Идет обмен пакетами мастер -> слейв, и обмен прекращается спустя 50-70 посылок.

Может кто подсказать в какую сторону копать ? (ошибка в мастере или слейве)

Код Слейва:
Спойлер
Код:
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <util/twi.h>
#include <avr/interrupt.h>
#include <stdlib.h>

#define data_port PORTD
#define data_ddr DDRD
#define cmd_port PORTB
#define cmd_ddr DDRB
#define DCS1 0
#define DCS2 1
#define DI 2
#define RW 3
#define E 4
#define RST 5

#define I2C_ADDR 0x30
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;
   }
}
volatile uint8_t data1=0;
volatile uint8_t data[6][3]={0};
volatile uint8_t flagStepFF=1;
volatile uint8_t flagJump=0;
volatile uint8_t flagCompleteReceiv=0;
volatile uint8_t FlagCompleteFill=0;
void I2C_received(uint8_t received_data)
{
   switch (flagStepFF)
   {
      case 1: if(received_data==0xFF) flagStepFF=2;break;
      case 2: if(received_data==0xFF) flagStepFF=3;break;
      case 3:
         if(received_data==0x00) {data[0][0]=received_data; flagStepFF=4;}
         if(received_data==0x01) {data[1][0]=received_data; flagStepFF=5;}
         if(received_data==0x02) {data[2][0]=received_data; flagStepFF=6;}
         if(received_data==0x03) {data[3][0]=received_data; flagStepFF=7;}
         if(received_data==0x04) {data[4][0]=received_data; flagStepFF=8;}
         if(received_data==0x05) {data[5][0]=received_data; flagStepFF=9;}
         flagJump=1;
      break;
      case 4:
         if(flagJump==0) {data[flagStepFF-4][2]=received_data;flagStepFF=1;break;}
         data[0][1]=received_data;
         flagJump=0;
      break;
      case 5:
         if(flagJump==0) {data[flagStepFF-4][2]=received_data;flagStepFF=1;break;}
         data[1][1]=received_data;
         flagJump=0;
      break;
      case 6:
         if(flagJump==0) {data[flagStepFF-4][2]=received_data;flagStepFF=1;break;}
         data[2][1]=received_data;
         flagJump=0;
      break;
      case 7:
         if(flagJump==0) {data[flagStepFF-4][2]=received_data;flagStepFF=1;break;}
         data[3][1]=received_data;
         flagJump=0;
      break;
      case 8:
         if(flagJump==0) {data[flagStepFF-4][2]=received_data;flagStepFF=1;break;}
         data[4][1]=received_data;
         flagJump=0;
      break;
      case 9:
         if(flagJump==0) {data[flagStepFF-4][2]=received_data;flagStepFF=1;flagCompleteReceiv=1;break;}
         data[5][1]=received_data;
         flagJump=0;
      break;
   }
   
}
void I2C_requested()
{
   I2C_transmitByte(data1);
}

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

   // init I2C
   I2C_init(I2C_ADDR);
}

PROGMEM const unsigned char FONTNUMBERS[10][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,0x0F,
   0x0F,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},
};
//uint8_t Nuber[6][3];

uint8_t BufferChar[6][4]={0};

/************************************************************************/
/* Функция отправки команды дисплею. ( lcd_cmd )                     */
/************************************************************************/
void lcd_cmd(unsigned char cmd)
{
   _delay_us(2);
   data_port = cmd;
   _delay_us(1);
   cmd_port |= (1<<E);
   _delay_us(12);
   cmd_port &= ~(1<<E);
   _delay_us(2);
}
/************************************************************************/
/* Функция отправки данных дисплею. ( lcd_data )                     */
/************************************************************************/
void lcd_data(unsigned char data,uint8_t FlagInvert)
{
   _delay_us(2);
   cmd_port |= (1<<DI);
   _delay_us(2);
   if(FlagInvert)
      data_port = data;
   else
      data_port = ~data;
   _delay_us(2);
   cmd_port |= (1<<E);
   _delay_us(12);
   cmd_port &= ~(1<<E);
   _delay_us(2);
   cmd_port &= ~(1<<DI);
   _delay_us(2);
}
/************************************************************************/
/* Функция инициализации дисплея. ( lcd_init )                         */
/************************************************************************/
void lcd_init()
{
   data_ddr = 0xFF;
   cmd_ddr |= (1<<DI)|(1<<RW)|(1<<E)|(1<<DCS1)|(1<<DCS2)|(1<<RST);
   cmd_port |= (1<<RST);
   cmd_port &=~((1<<DCS2)|(1<<DCS1));
   cmd_port |= (1<<DCS1);
   lcd_cmd(0x3F);
   cmd_port &=~((1<<DCS2)|(1<<DCS1));
   cmd_port |= (1<<DCS2);
   lcd_cmd(0x3F);
}
/************************************************************************/
/* Установка курсора на дисплее, ось X. (Верх/Низ) ( set_x )         */                
/************************************************************************/
void set_x(unsigned char pos_x)
{
   data_port = pos_x|0xB8;
   _delay_us(2);
   cmd_port |= (1<<E);
   _delay_us(12);
   cmd_port &= ~(1<<E);
   _delay_us(2);
}
/************************************************************************/
/* Установка курсора на дисплее, ось Y. (Лево/Право) ( set_y )         */
/************************************************************************/
void set_y(unsigned char pos_y)
{
   data_port = pos_y|0x40;
   _delay_us(2);
   cmd_port |= (1<<E);
   _delay_us(12);
   cmd_port &= ~(1<<E);
   _delay_us(2);
}
uint8_t lcd_send_block(uint8_t x,uint8_t y, uint8_t len, uint16_t addr,uint8_t FlagInvert)
{
   uint8_t i,col;

   if(y>63)
   {
      cmd_port &= ~(1<<DCS1);
      cmd_port |= (1<<DCS2);
      col = y-64;
   }
   else
   {
      cmd_port &= ~(1<<DCS2);
      cmd_port |= (1<<DCS1);
      col = y;
   }

   set_x(x);
   set_y(col);
   
   for(i=0;i!=len;i++,addr++,col++)
   {
      if(64==col)
      {
         if(cmd_port == (1<<DCS2))
         {
            return 128;
         }

         col=0;
         cmd_port &= ~(1<<DCS1);
         cmd_port |= (1<<DCS2);
         set_x(x);
         set_y(col);
      }

      lcd_data(pgm_read_byte(addr),FlagInvert);
   }
   return y+len;
}
void lcd_big_number(unsigned char Chip, uint8_t x, uint8_t y, uint16_t number,uint8_t FlagInvert)
{
   x=x*2;
   y=y*16;
   uint8_t i,col;
   uint16_t addr;
   addr= number*32;
   if(Chip == 2)
   {
      cmd_port &= ~(1<<DCS1);
      cmd_port |= (1<<DCS2);
      col = y;
   }
   else
   {
      cmd_port &= ~(1<<DCS2);
      cmd_port |= (1<<DCS1);
      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 avr_init()
{
   DDRC = 0x00;
   sei();
}
void FillBuffer()
{
   uint8_t Value[6];
   for (uint8_t tX = 0; tX < 6; tX++ )
   {
      Value[tX]=data[tX][2];
   }
   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;
         BufferChar[tX][i]   =TempResult;
      }
   }
   for (uint8_t tX = 0; tX < 6; tX++ )
   {
      BufferChar[tX][3]=data[tX][1];
   }
   FlagCompleteFill=1;
   flagCompleteReceiv=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],1);
         else
            lcd_big_number(2,tY,tX-3,BufferChar[tX][tY],0);
      }
   }
}
int main(void)
{
   avr_init();
   lcd_init();
   lcd_cmd(0xC0);
   setup();
   sei();
   while(1)
   {
      
      if(flagCompleteReceiv) FillBuffer();
      if(FlagCompleteFill) UpdateLCD();
   }
   return 0;
}

Мастера :
Спойлер
Код:
#define F_CPU 8000000UL

#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>


#define F_SCL 100000UL // SCL frequency
#define Prescaler 1
#define TWBR_val ((((F_CPU / F_SCL) / Prescaler) - 16 ) / 2)
//General Master staus codes
#define START       0x08    //START has been transmitted
#define REP_START   0x10
#define MT_DATA_ACK 0x28
#define MT_SLA_ACK  0x18

//Master Transmitter staus codes
#define MT_ADR_ACK      0x18   //SLA+W has been tramsmitted and ACK received
#define MT_ADR_NACK      0x20   //SLA+W has been tramsmitted and NACK received
#define MT_DATA_ACK      0x28   //Data byte has been tramsmitted and ACK received
#define MT_DATA_NACK   0x30   //Data byte has been tramsmitted and NACK received
#define MT_ARB_LOST      0x38   //Arbitration lost in SLA+W or data bytes
#define WRITE         0x00
#define READ         0x01
#define READ_END      0x01
#define READ_NOEND      0x00
#define ERROR         0x01
#define SUCCESS         0x00
#define I2C_ADR_SLAVE   0x30
// I2C
static uint8_t send_i2c(uint8_t value);
static uint8_t start_i2c(uint8_t d_adr);
static inline void stop_i2c();
static uint8_t write_i2c(uint8_t ADR, uint8_t value);

void i2c_init(void)
{
   TWBR = (uint8_t)TWBR_val;
}
//----------///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<<5)
#define BTN_LINE_DN      (1<<0)
//#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_PORT |= (BTN_LINE_UP| BTN_LINE_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_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;               //сброс счетчика длительности нажатия
   }
}
#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 (static unsigned char ValueCount = 0; ValueCount < CONFIG_AMOUNT; ValueCount++)
   {
      FlagPower[ValueCount]=ConfigLamp[ValueCount].FlagPower;
      ValuePWM[ValueCount]=ConfigLamp[ValueCount].ValuePWM;
   }
   */
   for (static unsigned char ValueCount = 0; ValueCount < CONFIG_AMOUNT; ValueCount++)
   {
      FlagPower[ValueCount]=1;
      ValuePWM[ValueCount]=ValueCount*20+15;
   }
   ValuePWM[5]=0xFF;
}

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));
}
//----------

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;}
   }
}
*/
void UpdateValue(void)
{
   for (unsigned char ValueCount = 0; ValueCount < CONFIG_AMOUNT; ValueCount++)
   {
      unsigned char TempValue=0;
      switch (ValueCount)
      {
         case 0:
         TempValue=OCR0A*2.56;
         if (FlagPower[ValueCount]==1)
         {
            if ((TempValue==0)&(!(ValuePWM[ValueCount]==0)))
            {
               while ((TempValue<ValuePWM[ValueCount])& (ValuePWM[ValueCount] < 99))
               {
                  //WriteSeg(ZoneNumber);
                  TempValue++;
                  _delay_ms(100);
                  OCR0A=TempValue;
               }
            }
            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;
      }
   }
}
ISR(INT0_vect)
{
   //WriteSeg(ZoneNumber);
   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();
   }
}
static uint8_t SendByte_i2c(uint8_t value)
{
   write_i2c((I2C_ADR_SLAVE<<1), value);
   asm("NOP");
   return 0;
}
uint8_t SendDataPack()
{
   for (unsigned char ValueCount = 0; ValueCount < CONFIG_AMOUNT; ValueCount++)
   {
      SendByte_i2c(0xFF);
      SendByte_i2c(0xFF);
      SendByte_i2c(ValueCount);
      SendByte_i2c(FlagPower[ValueCount]);
      SendByte_i2c(ValuePWM[ValueCount]);
      
   }
   return 0;
}
//char i=0;
int main(void)
{
   LoadingEEPROM();
   _delay_ms(50);
   init_io();
   init_int0();
   BtnInit();
   i2c_init();
   init_pwm();
   sei();
   while(1)
   {
      BtnUpdate();
      UpdateValue();
      SendDataPack();
   }
   return 0;
}
// I2C ////////////////////////////////////////
static uint8_t write_i2c(uint8_t ADR, uint8_t value) {
   uint8_t ret;
   if (start_i2c(ADR) != ERROR)
   {
      ret=send_i2c(value);
      stop_i2c();
      } else {
      stop_i2c();
      ret=ERROR;
   }
   return ret;
}
uint8_t send_i2c(uint8_t value)
{
   TWDR = value;
   TWCR = (1<<TWINT) | (1<<TWEN);
   // wail until transmission completed and ACK/NACK has been received
   while(!(TWCR & (1<<TWINT)));
   // check value of TWI Status Register. Mask prescaler bits.

   value = TWSR & 0xF8;
   return (value == MT_SLA_ACK || value == MT_DATA_ACK) ? SUCCESS : ERROR;
}
static uint8_t start_i2c(uint8_t d_adr)
{
   TWCR=(1<<TWINT) | (1<<TWSTA) | (1<<TWEN); // START
   while (!(TWCR & (1<<TWINT)));

   uint8_t twst = (TWSR & 0xF8); // check value of TWI Status Register. Mask prescaler bits.

   return ((twst != START) && (twst != REP_START)) ? ERROR : send_i2c(d_adr);
};
static inline void stop_i2c()
{
   TWCR=(1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
}
// END OF FILE ///////////////////////////////

Re: Ошибки В i2c обмен Atmega88 -> Atmega8

Вт сен 11, 2018 12:33:27

Ситуация в общем то типичная. Нужно просто на время обмена отключать прерывания.

Re: Ошибки В i2c обмен Atmega88 -> Atmega8

Ср сен 12, 2018 02:52:12

Уже тоже понял, время одного цикла (Прием + заполнения буфера + вывод на ЛСД) = почти 30 МС.
Ответить