标准串口通讯数据的格式为:起始位(1) + 数据位(8) + 校验位(1) + 停止位(1)
串口通讯另外一个重要的的部分是设置波特率,波特率就是1秒钟内串口所传输的Bit(位)数。
关于采样频率:为了较小读取或者发送串行数据的误差,我们采取了在N(我用的是4次)次中断中,取固定位置的读取的数据。
我以stm8中9600波特率计算的过程为例:(1秒钟传输9600位)
可以计算出传输1位所需要的时间 T1 = 1/9600 约为104us
由此可知,发送一位数据,定时器中断的时间间隔应为 104/4 = 26us(4倍采样频率)
stm8 内部晶振频率为16M,我采用8分频也就是2M,故MCU震荡周期为 1/2M = 0.5us
由上面的计算我们可以知道要发送一位数据,定时器中断的初值应设为为 26/0.5 =52
以上为相关数据的计算过程,下面是模拟串口驱动程序和注释:
定时器中断与IO口配置:
void TIM3_Configuration(void)
{
TIM3_DeInit();
TIM3_TimeBaseInit(TIM3_PRESCALER_8,52); //52 104
TIM3_ITConfig(TIM3_IT_UPDATE ,ENABLE);
TIM3_ARRPreloadConfig(ENABLE);
TIM3_Cmd(ENABLE); //DISABLE TIM3_Cmd(DISABLE)
}
//模拟串口引脚定义
#define SIM_UART_TX_PORT GPIOC
#define SIM_UART_TX_PIN GPIO_PIN_2
#define SimUartTxHigh() (SIM_UART_TX_PORT->ODR |= (u8)(SIM_UART_TX_PIN))
#define SimUartTxLow() (SIM_UART_TX_PORT->ODR &= (u8)(~SIM_UART_TX_PIN))
#define SIM_UART_RX_PORT GPIOC
#define SIM_UART_RX_PIN GPIO_PIN_3
#define SimUartRxStatus() (SIM_UART_RX_PORT->IDR & SIM_UART_RX_PIN)
GPIO_Init(SIM_UART_RX_PORT, SIM_UART_RX_PIN,GPIO_MODE_IN_PU_NO_IT);
GPIO_Init(SIM_UART_TX_PORT, SIM_UART_TX_PIN,GPIO_MODE_OUT_PP_LOW_FAST);
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
#include "global.h"
//默认采样频率为4倍 一下为16M晶振 8分频 后计数器的装载值
//9600B 104us发送一位 4倍采样频率 故为26us发送一位
#define SIM_BAUDRATE_9600 52
#define SIM_BAUDRATE_4800 104
#define SIM_BAUDRATE_2400 208
/* Private variables ---------------------------------------------------------*/
u8 RxByteIndex; //接收字节索引
u8 RxSampFreq; //采样频率控制 1/4
u8 TxXKCnt = 3; //需要发送数据包的字节数
u8 SimUartRxBuff[10]; //接收数据包缓冲
u8 SimUartTxBuff[10] = {0x55, 0xaa, 0x66};
bool IsSimUartRxFinish;//是否接收完成标志
bool IsSimUartRecv; //模拟串口是否处于接收状态
/* Private functions ---------------------------------------------------------*/
/* Public functions ----------------------------------------------------------*/
void InterruptSimUart(void);
static void Drv_SimUartTxByte(void);
static void Drv_SimUartRxByte(void);
/*******************************************************************************
#Function : InterruptSimUart
#Description : 模拟串口中断调用程序 切换发送与接收
#Parameter : NULL
#Return : NULL
#AuthorAndData : huangzhigang 20141013
*******************************************************************************/
void InterruptSimUart(void)
{
if(IsSimUartRxFinish) //接收完成后立刻发送数据 也可以自己定义什么时候发送数据
{
IsSimUartRxFinish = FALSE;
IsSimUartRecv = FALSE;
}
if(IsSimUartRecv)
{
Drv_SimUartRxByte();
}
else
{
Drv_SimUartTxByte();
}
}
/*******************************************************************************
#Function : Drv_SimUartRxByte
#Description : 模拟串口接收函数
#Parameter : NULL
#Return : NULL
#AuthorAndData : huangzhigang 20141013
*******************************************************************************/
static void Drv_SimUartRxByte(void)
{
static u8 RxBitNum; //接收位计数
static u8 Verify; //校验码
static u8 OverTime; //接收超时计数
static u8 s_u8Rxbuff; //一字节接收缓存
if(SimUartRxStatus())
{
OverTime++;
}
else
{
OverTime = 0;
}
if(OverTime > 44)
{
OverTime = 45;
RxByteIndex = 0;
RxBitNum = 0;
}
if((SimUartRxStatus()) && (RxBitNum == 0))
{
RxSampFreq = 0;
}
else
{
++RxSampFreq;
}
if(RxSampFreq == 1)
{
if(RxBitNum == 0) //低电平,起始位bit0
{
if(!SimUartRxStatus())
{
Verify = 0;
s_u8Rxbuff = 0;
RxBitNum++;
}
}
else if((RxBitNum > 0) && (RxBitNum < 9)) //数据位 bit1~8
{
if(SimUartRxStatus()) //高电平
{
s_u8Rxbuff = s_u8Rxbuff | (0x01 << (RxBitNum -1));
Verify++;
}
RxBitNum++;
}
else if(RxBitNum == 9) //校验位 bit9
{
RxBitNum++;
if(Verify & 0x01)
{
if(SimUartRxStatus()) {RxBitNum = 0;} //奇校验
}
else
{
if(!SimUartRxStatus()) {RxBitNum = 0;}
}
}
else if(RxBitNum == 10) //停止位 bit10
{
if(SimUartRxStatus())
{
RxBitNum = 0;
if(RxByteIndex == 0) //头码1为0X55
{
if(s_u8Rxbuff == 0x55)
{
SimUartRxBuff[RxByteIndex] = s_u8Rxbuff;
RxByteIndex++;
}
else
{
RxByteIndex = 0;
}
//TEST 测试 接收到一字节数据后马上回复
// IsSimUartRxFinish = TRUE;
}
else if(RxByteIndex == 1) //头码2为0Xaa
{
if(s_u8Rxbuff == 0xaa)
[1] [2]