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