Звероящер (25.03.2016 20:00, просмотров: 11377)
Странное поведение таймера у 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); // Проверка таймингов
}
}
/******************************************************************************/