基于STM8普通IO口的模拟串口驱动程序
标准串口通讯数据的格式为:起始位(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 <span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;">InterruptSimUart</span><span style="font-size: 12px; font-family: Arial, Helvetica, sans-serif;">(void);</span> 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) { SimUartRxBuff[RxByteIndex] = s_u8Rxbuff; RxByteIndex++; } else { s_u8Rxbuff = 0; } } else { SimUartRxBuff[RxByteIndex] = s_u8Rxbuff; RxByteIndex++; if(RxByteIndex >= 2) //接收完一个数据包 { //TODO: 20141013 hzg 验证校验码 RxByteIndex = 0; IsSimUartRxFinish = TRUE; } } } } else { RxBitNum = 0; } } else if(RxSampFreq > 3) { RxSampFreq = 0; } } /******************************************************************************* #Function : Drv_SimUartTxByte #Description : 模拟串口发送函数 #Parameter : NULL #Return : NULL #AuthorAndData : huangzhigang 20141013 *******************************************************************************/ void Drv_SimUartTxByte(void) { static bool SendFinish = TRUE; //发送完成标志 static u8 Verify; //奇偶校验 static u8 TxSampFreq = 0; //发送计数 采样4次 static u8 BitNum = 0; //位计数 static u8 ByteLock; //发送字节锁定(防止在发送途中 发送数字被改变) static u8 TxIndex = 0; //当前发送索引 if(SendFinish) { SendFinish = FALSE; RxSampFreq = 0; BitNum = 0; if(TxIndex < TxXKCnt) //控制发送的字节 { ByteLock = SimUartTxBuff[TxIndex]; TxIndex++; RxByteIndex = 0; } else { IsSimUartRecv = TRUE; SendFinish = TRUE; TIM3->ARRH = (uint8_t)(52 >> 8); //定时器3计数器重装初值 TIM3->ARRL = (uint8_t)(52); // TxXKCnt = 0; TxIndex = 0; } } if(++TxSampFreq > 3) { if(BitNum == 0) //起始位 { Verify = 0; SimUartTxLow(); BitNum++; } else if((BitNum >0) && (BitNum < 9)) //数据位 { if(0x01 & (ByteLock >> (BitNum-1))) //先发低位 { SimUartTxHigh(); Verify++; } else { SimUartTxLow(); } BitNum++; } else if(BitNum == 9) //校验位 { if(0x01 & Verify) //奇校验 { SimUartTxLow(); //有奇数个1 则发送0 } else { SimUartTxHigh(); //有偶数个1则发送1 } BitNum++; } else if(BitNum == 10) //停止位 { SimUartTxHigh(); SendFinish = TRUE; BitNum = 0; } TxSampFreq = 0; } }
原文地址:http://blog.csdn.net/a656343072/article/details/40047591