ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Пятница
29 ноября
662984
Звероящер (25.03.2016 20:00, просмотров: 11369)
Странное поведение таймера у STM8. Сегодня натолкнулся на такую проблему: В общем есть программный уарт. Для его проверки я замкнул ТХ аппаратного уарта на софтварный пин и принимаю байт. Использую таймер2 TIM2 для отсчета полубайта и байта при приёме. Так вот, почему-то таймер повторно не инициализируется другим значением при приёме. Через отладчик (ST-Link) гляжу - все регистры взводятся как надо, всё клокает верно. В железяке - хрен. Кто что скажет? Код - ниже. #include <iostm8s003f3.h> #include "stm8s_type.h" #include <intrinsics.h> #define LEDDATAPORT PC_ODR #define LEDDATAPIN PC_IDR #define LEDgreen 4 #define LEDred 3 #define OUTPUTDATAPORT PD_ODR #define OUTPUTDATAPIN PD_IDR #define OUTPUTDATADIR PC_DDR #define DataTXIn 5 #define DataRXIn 6 #define DataRight 3 #define DataLeft 2 #define DataForward 4 #define SETBIT(ADDRESS, BIT) ((ADDRESS) |= (1<<(BIT))) #define CLEARBIT(ADDRESS, BIT) ((ADDRESS) &= ~(1<<(BIT))) #define TESTBIT(ADDRESS, BIT) ((ADDRESS) & (1<<(BIT))) #define TOGGLEBIT(ADDRESS, BIT) ((ADDRESS) ^= (1<<(BIT))) /******************************************************************************/ void InitialiseSystemClock() // Частота 16 МГц { CLK_CKDIVR = 0; CLK_SWR = 0xe1; CLK_SWCR = 0; CLK_SWCR_SWEN = 1; while (CLK_SWCR_SWBSY != 0); } /******************************************************************************/ void LEDinit() { PC_DDR |= (1<<LEDgreen) | (1<<LEDred); // Порты на выход PC_ODR |= (1<<LEDgreen) | (1<<LEDred); // } /******************************************************************************/ void Timer1msInit() { // Установка Таймера 4 для прерывания в 1мсек TIM4_PSCR = 7; // Prescaler TIM4_ARR = 0x7c; // Reloading Counter TIM4_IER = 1; // Enable interrupt TIM4_CR1 = 0x81; // Enable timer with autoreloading } /*----------------------------------------------------------------------------*/ vu16 timer = 0; #pragma type_attribute = __interrupt #pragma vector = TIM4_OVR_UIF_vector void Timer1msInterrupt() { /* Прерывание вызывается раз в 1 мсек */ TIM4_SR = 0; timer++; } /*----------------------------------------------------------------------------*/ /******************************************************************************/ void OutputsInit() { PD_DDR |= (0<<DataRight) | (1<<DataLeft) | (1<<DataForward); // Три выхода PD_CR1 |= (1<<DataRight) | (1<<DataLeft) | (1<<DataForward); // Выходы push-pull PD_CR2 |= (0<<DataRight) | (1<<DataLeft) | (1<<DataForward); // Выходы push-pull PD_ODR |= (1<<DataRight) | (1<<DataLeft) | (1<<DataForward); // Всё в единицу EXTI_CR1_PDIS = 2; } /*----------------------------------------------------------------------------*/ #define STOPOUTPUTTIMER TIM2_CR1 = 0; // Disable timer with autoreloading #define STARTOUTPUT_1TIMER TIM2_ARRH = 0x3; TIM2_ARRL = 0x7f; TIM2_EGR_UG = 1; TIM2_SR1 = 0; TIM2_CR1 = 0x85; // Enable timer with autoreloading #define STARTOUTPUT_2TIMER TIM2_ARRH = 0x6; TIM2_ARRL = 0x7f; TIM2_EGR_UG = 1; TIM2_SR1 = 0; TIM2_CR1 = 0x85; // Enable timer with autoreloading /*----------------------------------------------------------------------------*/ void TransmitOutputByte(u8 data) { u8 i = 7; u8 irq = PD_CR2; PD_CR2 = 0; SETBIT(OUTPUTDATADIR, DataLeft); // конфигурируем как выход CLEARBIT(OUTPUTDATAPORT, DataLeft); // Стартбит STARTOUTPUT_1TIMER; while(!TIM2_SR1_UIF) ; TIM2_SR1 = 0; do { STARTOUTPUT_1TIMER; if(data & 0x1) SETBIT(OUTPUTDATAPORT, DataLeft); else CLEARBIT(OUTPUTDATAPORT, DataLeft); data >>= 1; while(!TIM2_SR1_UIF) ; TIM2_SR1 = 0; } while(i--); SETBIT(OUTPUTDATAPORT, DataLeft); // Стопбит while(!TIM2_SR1_UIF) ; TIM2_SR1 = 0; STOPOUTPUTTIMER; CLEARBIT(OUTPUTDATADIR, DataLeft); // конфигурируем как вход PD_CR2 = irq; // Включаем прерывание } /*----------------------------------------------------------------------------*/ vu8 ReceivedByte, ReceiveByteStatus; #pragma type_attribute = __interrupt #pragma vector = EXTI3_vector void ReceiveOutputByte() { CLEARBIT(LEDDATAPORT, LEDgreen); u8 irq = PD_CR2; // Сохраняем конфиг ног PD_CR2 = 0; // Отключаем внешнее преывание по ноге ReceivedByte = 0; u8 i = 7; STARTOUTPUT_2TIMER; while(!TIM2_SR1_UIF) ; TIM2_SR1 = 0; // Отсчитали полбайта стартового бита SETBIT(LEDDATAPORT, LEDgreen); STARTOUTPUT_1TIMER; while(!TIM2_SR1_UIF) ; TIM2_SR1 = 0; // Отсчитали байт. Попали на середину первого бита do { CLEARBIT(LEDDATAPORT, LEDgreen); STARTOUTPUT_1TIMER; if(TESTBIT(OUTPUTDATAPIN, DataRight)) ReceivedByte |= 0x80; ReceivedByte >>= 1; while(!TIM2_SR1_UIF) ; TIM2_SR1 = 0; SETBIT(LEDDATAPORT, LEDgreen); } while(i--); if(TESTBIT(OUTPUTDATAPIN, DataRight)) ReceiveByteStatus = 1; // Есть стоп-бит else ReceiveByteStatus = 0; STOPOUTPUTTIMER; PD_CR2 = irq; // Включаем прерывание } /******************************************************************************/ void InputInit() { PD_DDR |= (1<<DataTXIn) | (0<<DataRXIn); // PD_CR1 |= (1<<DataTXIn) | (0<<DataRXIn); // PD_CR2 |= (0<<DataTXIn) | (0<<DataRXIn); // // UART init UART1_BRR2 = 0x03; UART1_BRR1 = 0x68; // Скорость 9600 UART1_CR2 = 0; // запретить прерывания передачи UART1_SR = 0; // сбросить флаг приёма байта UART1_CR2_REN = 0; // Включить приёмник UART1_CR2_TEN = 1; // Включить передатчик } u8 TransmitInputByte(u8 data) { if(!UART1_SR_TXE) return 0; UART1_DR = data; return 1; } /******************************************************************************/ void main() { InitialiseSystemClock(); LEDinit(); Timer1msInit(); InputInit(); OutputsInit(); __enable_interrupt(); u8 status; while(1) { while (timer < 500) ; timer = 0; TOGGLEBIT(LEDDATAPORT, LEDred); UART1_SR_TC = 0; status = TransmitInputByte(0x71); while(!UART1_SR_TC) ; TransmitOutputByte(ReceivedByte); // TransmitOutputByte(0x71); // Проверка таймингов } } /******************************************************************************/