AVR Раздел по микроконтроллерам компании Atmel - AVR / ATtiny / ATmega / ATMega128 / ATxmega, вопросы по программированию в AVR studio и все, относящееся к AVR... |
09.07.2016, 00:18
|
|
Частый гость
Регистрация: 16.05.2016
Адрес: Москва
Сообщений: 35
Сказал спасибо: 6
Сказали Спасибо 1 раз в 1 сообщении
|
TWI конечный автомат на прерываниях
Здравствуйте уважаемые форумчане! Написал программу для мк мега16 обмена данными с модулем по шине TWI, сделал все на прерываниях. Но к сожалению когда " каруселька" автомата начинает крутится на одном из значений происходит crash, а именно сохраненные данные с модуля в массиве перезаписываются неизвестными, а индекс следующего шага автомата перезаписывается первым шагом и все начинается с начала и так по кругу бесконечное прерывание... Я не знаю где скрылась ошибка, в коде все кажется логично и правильно тем более в своем помогите советом компетентные люди
Нажмите, чтобы открыть спойлер
Код:
|
#include "LCD_HD44780.h"
#include "TWI.h"
#include "UART.h"
#include ‹util/delay.h›
#include ‹stdio.h›
#include ‹stdint.h›
#include ‹stdbool.h›
enum measure_mode
{
accel_xh,
accel_xl,
accel_yh,
accel_yl,
accel_zh,
accel_zl,
hyro_xh,
hyro_xl,
hyro_yh,
hyro_yl,
hyro_zh,
hyro_zl,
temperature_h,
temperatyre_l
};
int array_adress[] =
{ ACCEL_XOUT_H, ACCEL_XOUT_L, ACCEL_YOUT_H, ACCEL_YOUT_L, ACCEL_ZOUT_H, ACCEL_ZOUT_L,
GYRO_XOUT_H, GYRO_XOUT_L, GYRO_YOUT_H, GYRO_YOUT_L, GYRO_ZOUT_H, GYRO_ZOUT_L,
TEMP_OUT_H, TEMP_OUT_L };
enum measure_mode current = accel_xh;
char data[15];
uint8_t Flag = 1;
uint8_t reg_adress;
ISR(TWI_vect)
{
cli();
switch(get_status())
{
case TW_BUS_FAIL://аппаратная ошибка шины
break;
case TW_START://отправлено условие старт(1)
I2C_tranciv_byte(MPU_6050_ADDRESS_W);//вот после этого шага на индексе hyro_xl все рушится и следующий шаг записывается индекс accel_xh и так по кругу(((
break;
case ReStart://отправлен повторный старт(4)
I2C_tranciv_byte(MPU_6050_ADDRESS_R);
break;
case TW_MT_AD_ACK://ведущий послал адрес ведомого с битом для записи ведомый отозвался(2)
PORTD ^= 1‹‹PD7;
reg_adress = array_adress[(int)current];
I2C_tranciv_byte(reg_adress);
break;
case TW_MT_AD_NACK://ведущий послал адрес ведомого с битом для записи ведомый не отозвался
kursor_adress(FIRST);
LCD_write_str("ERROR SLAVE_NACK");
break;
case TW_MT_DATA_ACK://ведущий послал данные и принял подтверждение (3)
I2C_start();
break;
case TW_MT_DATA_NACK://ведущий послал данные и не принял подтверждение
break;
case TW_MR_AD_ACK://ведущий послал адрес ведомого с битом для чтения ведомый отозвался(5)
data[(int)current] = I2C_receiver_last_byte();
break;
case TW_MR_AD_NACK://ведущий послал адрес ведомого с битом для чтения ведомый не отозвался
break;
case TW_MR_DATA_ACK://ведущий принял данные и передал подтверждение
break;
case TW_MR_DATA_NACK://ведущий принял последний байт и передал NACK(6)
I2C_stop();
if(current == temperatyre_l)
{
PORTB ^= 1‹‹PB3;
current = accel_xh;
Flag = 1;
}
else
{
current++;
I2C_start();
}
break;
}
sei();
}
int main()
{
I2C_init();// инициализация шины TWI
LCD_init();
DDRD = 1‹‹PD5|1‹‹PD4|1‹‹PD7;
DDRB = 1‹‹PB3;
PORTD = 0‹‹PD5|0‹‹PD4|0‹‹PD7;
sei();
I2C_start();
for(;;)
{
while(Flag)
{
cli();
char buffer[4];
int16_t ACCEL_X = data[(int)accel_xh]‹‹8|(data[(int)accel_xl]&0xF0);
int16_t ACCEL_Y = data[(int)accel_yh]‹‹8|(data[(int)accel_yl]&0xF0);
int16_t ACCEL_Z = data[(int)accel_zh]‹‹8|(data[(int)accel_zl]&0xF0);
int16_t GYRO_X = data[(int)hyro_xh]‹‹8|(data[(int)hyro_xl]&0xF0);
int16_t GYRO_Y = data[(int)hyro_yh]‹‹8|(data[(int)hyro_yl]&0xF0);
int16_t GYRO_Z = data[(int)hyro_zh]‹‹8|(data[(int)hyro_zl]&0xF0);
int16_t TEMPERATURE = data[(int)temperature_h]‹‹8|data[(int)temperatyre_l];
TEMPERATURE = TEMPERATURE/340+36;
static _Bool is_init;
if(!is_init)
{
kursor_adress(FIRST);
LCD_write_str("A:000 000 000 t=");
kursor_adress(SEC_LINE);
LCD_write_str("H:000 000 000 000");
is_init = true;
}
itoa(ACCEL_X, buffer, 10);
kursor_adress(THIRD);
LCD_write_str(buffer);
itoa(ACCEL_Y, buffer, 10);
kursor_adress(SEVENTH);
LCD_write_str(buffer);
itoa(ACCEL_Z, buffer, 10);
kursor_adress(ELEVENTH);
LCD_write_str(buffer);
itoa(GYRO_X, buffer, 10);
kursor_adress(THIRD_S);
LCD_write_str(buffer);
itoa(GYRO_Y, buffer, 10);
kursor_adress(SEVENTH_S);
LCD_write_str(buffer);
itoa(GYRO_Z, buffer, 10);
kursor_adress(ELEVENTH_S);
LCD_write_str(buffer);
itoa(TEMPERATURE, buffer, 10);
kursor_adress(FIFTEENTH_S);
LCD_write_str(buffer);
_delay_ms(40);
Flag = 0;
I2C_start();
sei();
}
}
return 0;
} |
|
|
|
|
09.07.2016, 10:43
|
|
Заблокирован
Регистрация: 07.09.2014
Адрес: В Кремле!
Сообщений: 4,486
Сказал спасибо: 396
Сказали Спасибо 2,220 раз(а) в 1,319 сообщении(ях)
|
Re: TWI конечный автомат на прерываниях
Ну значит, где-то было сделано не логично...
Бесконечное прерывание? Значит, не сбрасывается флаг прерывания.
|
|
|
|
09.07.2016, 11:17
|
|
Почётный гражданин KAZUS.RU
Регистрация: 20.03.2007
Адрес: "Братское кольцо враждебности", т.е. ближайшее заМКАДье.
Сообщений: 6,947
Сказал спасибо: 2,993
Сказали Спасибо 3,170 раз(а) в 2,151 сообщении(ях)
|
Re: TWI конечный автомат на прерываниях
Да и исходников мало. Нет функций I2C_***, верно-ли определены константы (TW_BUS_FAIL и т.д.) для разбора состояний TWSR.
Сообщение от NewWriter
|
Бесконечное прерывание? Значит, не сбрасывается флаг прерывания.
|
Кстати - да. TWINT нужно сбрасывать программно перед "sei()", сам он не сбрасывается.
Последний раз редактировалось ForcePoint; 09.07.2016 в 11:20.
Причина: Дополнение про сброс флага.
|
|
|
|
09.07.2016, 12:50
|
|
Гражданин KAZUS.RU
Регистрация: 16.03.2011
Сообщений: 486
Сказал спасибо: 8
Сказали Спасибо 131 раз(а) в 116 сообщении(ях)
|
Re: TWI конечный автомат на прерываниях
Сообщение от ForcePoint
|
нужно сбрасывать программно перед "sei()", сам он не сбрасывается.
|
sei и cli в прерывании не нужны - при входе в прерывание бит I устанавливается в 0. При выходе из прерывания устанавливается в 1 командой reti.
|
|
|
Сказали "Спасибо" _Артём_
|
|
|
09.07.2016, 13:13
|
|
Почётный гражданин KAZUS.RU
Регистрация: 20.03.2007
Адрес: "Братское кольцо враждебности", т.е. ближайшее заМКАДье.
Сообщений: 6,947
Сказал спасибо: 2,993
Сказали Спасибо 3,170 раз(а) в 2,151 сообщении(ях)
|
Re: TWI конечный автомат на прерываниях
Сообщение от _Артём_
|
sei и cli в прерывании не нужны - при входе в прерывание бит I устанавливается в 0. При выходе из прерывания устанавливается в 1 командой reti.
|
Да.
cli() это не смертельно. А вот sei() без сброса TWINT помимо постоянного "шлёпанья" этого прерывания вызовет и переполнение стека, т.к. текущее прерывание не будет доходить reti когда оно-же вызовется снова.
|
|
|
Сказали "Спасибо" ForcePoint
|
|
|
09.07.2016, 16:46
|
|
Частый гость
Регистрация: 16.05.2016
Адрес: Москва
Сообщений: 35
Сказал спасибо: 6
Сказали Спасибо 1 раз в 1 сообщении
|
Re: TWI конечный автомат на прерываниях
Всем спасибо убрал cli и sei в прерываниях, сделал сброс флага TWINT перед sei и все заработало!)))
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 19:09.
|
|