STM32使用IO口模拟串口
期望效果:
使用普通IO模拟串口,实现非阻塞全双工通讯功能。
硬件资源:
1.2个IO口
2.1个外部中断
3.1个定时器
串口相关知识简述:
1.波特率
波特率,即每秒传输的位个数。例9600bps,即每秒传输9600个bit,每位电平状态保持时长为:t = 1000000/9600 ≈104.16us
2.时序
1个起始位+8个数据位+1个停止位
注:起始位为低电平,停止位为高电平,数据位低有效位在前。空闲状态下,TX Line和RX Line均为高电 平。
初始化:
发送IO口配置为推挽输出模式,并设置初始电平状态为高电平。接收IO口配置为上拉输入模式。定时器配置为向上计数模式并使能更新中断,每隔104us产生一次中断事件。外部中断配置为下降沿触发模式,当检测到下降沿时,产生一次中断事件。
发送:
先将待发送数据存入FIFO(先入先出队列)中,然后从FIFO中取出首字节赋值到文件全局变量txData,并置位发送txFlag和清零发送位计数器txBitCount。在定时器中断事件中执行发送。示意代码如下所示:
if( txFlag )
{
if( txBitCount == 0 ) //发送起始位
{
PIN_CLR( TX );
txBitCount++;
}
else if( txBitCount < 9 ) //发送8个数据位
{
(txData & 0x01)? PIN_SET( TX ):PIN_CLR( TX );
txData >>= 1;
txBitCount++;
}
else if( txBitCount == 9 ) //发送1个停止位
{
PIN_SET( TX );
txBitCount++;
}
else //检查FIFO中是否有未发送数据
{
if( txFifo.count )
{
txData = txFifo.buf[txFifo.head];
txFifo.head++;
txFifo.head &= txFifo.mask;
txFifo.count--;
txBitCount = 0;
}
else
{
txFlag = 0;
}
}
}
接收:
当产生外部中断事件时,置位接收标志rxFlag,并清零接收位计数器rxBitCount,然后在定时器中断事件中采样数据。将采样到的位数据暂存到文件全局变量rxData中,采样结束后将rxData存入接收FIFO中。示意代码如下所示:
if( rxFlag )
{
if( rxBitCount < 9 ) //接收起始位和数据位
{
rxData >>= 1;
if( PIN_READ( RX ) == SET )
{
rxData |= 0x80;
}
rxBitCount++;
}
else //判断停止位
{
if( PIN_READ( RX ) == SET ) //有效停止位
{
rxFifo.buf[rxFifo.tail] = rxData;
rxFifo.tail++;
rxFifo.tail &= rxFifl.mask;
rxFifo.count++;
}
rxFlag = 0;
rxBitCount = 0;
}
}
结尾:
经过测试,实现了非阻塞全双工通讯功能,但是接收数据不太稳定,尚需优化。如果对正确率要求不高(如本打字员,仅在生产时使用该串口配置下设备参数,一次不成,可以再来个2345下),那么还是可以凑合使用的。
纯手打,难免手滑,如有错误,您可得海涵。
/**************************************End*************************************/