最近想利用单片机的IO口模拟UART,要求可以实现高波特率发送,查阅了ST的官网,发现了编号为 AN4457 Application note 的文档有介绍:Implementing an emulated UART on STM32F4 microcontrollers 顿时发现了一扇新大门啊。另外又参考了阿莫电子的一篇文章:在STM32上实现高性能模拟UART。这里复制原文内容如下:

可以这样实现:以通讯格式9600,8N1为例:

  1. 将TIM2(或TIM3)的周期设为波特率周期约104us,设一个通道的比较匹配值为52us;
  2. 发送时,仅开启计数溢出触发DMA,设置DMA搬运次数为10(1个起始位, 8个数据位,1个停止位),格式化要发送的数据保存到发送数组中(注解),
  3. 设置DMA把发送数组的数据搬运到GPIO;
  4. 然后启动定时器,当DMA搬运完成时,这个字节就发送完毕了;
  5. 接收时,仅开启计数匹配触发DMA,设置DMA搬运次数为10,设置DMA把GPIO搬运到接收数组,设置RX脚下降沿触发IO中断;
  6. 当IO中断触发时,清零定时器并启动;  当DMA搬运完成中断触发时,停止定时器,此时字节已经接收完毕;
  

注解:
    以TX脚位为PIN4,发送0x23为例,定义一个10元素的数组,元素长度为16bit(对应GPIO位宽);
    格式化后的10个元素依次为:
    起始位  :XXXX XXXX XXX0 XXXX
    数据位0:XXXX XXXX XXX0 XXXX
    数据位1:XXXX XXXX XXX1 XXXX
    数据位2:XXXX XXXX XXX0 XXXX
    数据位3:XXXX XXXX XXX0 XXXX
    数据位4:XXXX XXXX XXX1 XXXX
    数据位5:XXXX XXXX XXX1 XXXX
    数据位6:XXXX XXXX XXX0 XXXX
    数据位7:XXXX XXXX XXX0 XXXX
    停止位  :XXXX XXXX XXX1 XXXX

 

另注:用DMA直接搬运数据到IO会干扰GPIO上其他处于输出状态的IO,

解决这个问题有2个办法:


 1.使用其他IO都是输入模式的GPIO作为TX脚(如STM32的GPIOC和GPIOD,pin脚少,容易实现仅一个输出模式的IO);

 2.把DMA的目标地址设为GPIO_BSRR即可,但要注意数组格式化的方法不同,元素长度变为32bit,要置位pin脚时使用低16bit,清零pin脚时用高16bit;

但是自己项目上要求只需要多个口进行并行的多串口输出,按照这个思路,最大的缺点应该就是比较消耗内存了,为此,想到了一种优化数据传输的方法,利用M3内核片子自带的位带操作,将每次数据传输的位数扩展到32bit直接操纵BSRRL寄存器,这样就极大的节省了数据内存,只要定义一个32bit的缓存数据,在每次要传输数据时,利用位带操作,翻转改变量的值后赋值到BSRRL寄存器即可,这里利用了一下两个特性

BSRRL 表示BSRR寄存器低16位(BSy),哪一个BRy置1,引脚输出高电平

BSRRH 表示BSRR寄存器高16位(BRy),哪一个BRy置1,引脚输出低电平

可方便的将IO口进行并行输出的同时,也同时完成了多个模拟串口的并行数据,一举两得啊。