今天我们来了解一下合泰芯片的串口通信,先来看一下核心板电路,可以发现PA3是RX口,PA7是TX口,但是PA7口在前面的蜂鸣器驱动中复用为GPIO口,在使用前需要把0R电阻JR1拆掉,否则可能会出现奇奇怪怪的问题。

        看到芯片手册163页,流程图展示了数据发送和接收流程,数据发送时先发到TXR寄存器然后送到移位寄存器发送数据,数据从低位到高位发出。接收时移位寄存器先接收,然后再发送,在发送和接收时速率都是由波特率发生器控制。

        在164页的UARTn数据传输方案中,对数据传输的流程也有详细的描述,但是要注意接收寄存器和发送寄存器是共用一个数据寄存器,也就是说发送和接收的数据都在一个地方,如果发生冲突,例如中断接收把发送的数据冲掉,那此时发送的数据是有问题的,一般不会遇到,但是在同时接收和发送数据时需要注意。

        接下来开始配置寄存器,一共有5个寄存器,UnSR是只读寄存器,这个寄存器会存储UART的状态,我们无需配置。第二个是控制寄存器,Bit7是使能UART,所以设置为1,发送数据位选择8Bit,Bit6=0;无奇偶校验,Bit5-4均为0;停止位为1,Bit3为0;暂停字设置无,Bit2为0;Bit1为只读,设置为0;Bit0是发送9位数据才有效,这里无需配置,也默认为0;UnCR1寄存器配置为0x10000000=0x80。

        然后是UnCR2寄存器配置,这里Bit7是UARTn的发送使能,配置为1;Bit6的RXENn是接收使能,配置为1;Bit5是波特率的速度选择,这里设置为低速,配置为0;Bit4的地址位检测设置为0;Bit3无需配置,设置为0;Bit2是接收中断使能,配置为1;Bit1的发送空闲中断使能配置为0;Bit0的寄存器为空也选择默认,配置为0。因此UNCR2为0x11000100=0xc4。

               

        TXR_RXRn是数据寄存器,用来存储发送和接收的数据,这里我们配置为0xff,0x00等都没有影响。BRGn寄存器是设置波特率的寄存器,在前面设置UnCR2时会影响到这里的速度,这里我们把波特率设置为9600,带入公式也就是:9600=fH/[64*(N+1)],,fH为8M,解得N=12,所以这里配置为BRGn=0x0c。这里带入公式有朋友可能有疑惑,算一下不难发现N不是刚刚好等于12,有一定的误差,但是不影响我们使用。

                       

        配置完串口通信的基础后,看到178页的中断地图,可以看到UART0中断在优先级比较低的地方,先打开UART0的中断,UR0E=0,然后开启总中断,EMI=0。到这里我们已经配置完串口通信的基础设置,然后来写一个简单的逻辑,用核心板发送字符串1和2,分别控制PB6和7的两个LED,让他们不断翻转,并且速度不能太快。

        代码写完后可以使用USB转ttl来和核心板通信,如果手上有两个核心板也可以同时烧录这个程序,都可以实现上述功能。在这里笔者用两种方式都尝试过,在最开始代码逻辑没写好,遇到总线冲突,发现用USB转ttl单独通信没问题,两块核心板通信就会出问题,花费一点时间后找到原因,调了代码的顺序就解决了这个问题。

#include "BS86D20C.h"

#define u16 unsigned int
#define u8 unsigned char
#define IN  1   // 引脚方向:输入
#define OUT 0   // 引脚方向:输出

#define ON  1   // LED 亮
#define OFF 0   // LED 灭

unsigned int a;          // 主循环计数器,用于“软件延时”
volatile u8 recdata = 0; // 串口收到的最新字节,由中断写入

void delay_ms(u16 ms)
{
    while(ms--)
    {
        GCC_DELAY(2000); // 约 1 ms(8 MHz 时 2000 个空指令周期)
        GCC_CLRWDT();    // 喂狗,防止 WDT 复位
    }
}

//UART串口通信
void UART_SendChar(u8 data)
{
    if(_txif0)              // TX 寄存器空才可写
    {
        _txr_rxr0 = data;   // 写入 TXR,同时硬件清 TXIF
        while(!_txif0);     // 等待数据被移入移位寄存器
        while(!_tidle0);    // 等待全部位发送完毕
    }
}

void SendString(u8 *ch)//发字符串
{
	while(*ch!=0)   // 遇到 '\0' 结束
	{
		UART_SendChar(*(ch++));
	}	
}

void main()
{
    /* ---- 1. 配置 LED 引脚 ---- */
    _pbc6 = OUT;    // PB6 设为输出
    _pbc7 = OUT;    // PB7 设为输出
    _pb6  = ON;     // LED1 初始亮
    _pb7  = OFF;    // LED2 初始灭

    /* ---- 2. 配置 UART 引脚 ---- */
    _pac7 = 0;      // PA7 设为输出(TX)
    _pa7  = 1;      // TX 默认高
    _pac3 = 1;      // PA3 设为输入(RX)
    _papu3 = 1;     // RX 开内部上拉

    /* ---- 3. 配置 UART 寄存器 ---- */
    _u0cr1 = 0x80;  // 使能 UART0,8 位数据
    _u0cr2 = 0xC4;  // 允许发送、接收,1 位停止位
    _txr_rxr0 = 0xFF; // 先清一次 RX 寄存器
    _brg0 = 0x0c;     // 波特率 9600(8 MHz 时钟)

    /* ---- 4. 开中断 ---- */
    _ur0e = 1;      // 允许 UART0 接收中断
    _emi  = 1;      // 开总中断
	
	delay_ms(20);   // 上电后等晶振稳定

    while (1)
    {
    	a++;     // 计数器自增
        _clrwdt();//喂狗
    	if(a>65534)//自增延时,如果a=65535(最大值,再大就溢出),发送1,2
    		{
	       		SendString((u8*)"1\n");
	        	SendString((u8*)"2\n");
          	    a = 0;
    		}
        if (recdata != 0)   
        {
            if (recdata == '1')   
            {
                _pb6 = ~_pb6;
            }
            else if (recdata == '2')   
            {
                _pb7 = ~_pb7;
            }
            recdata = 0;  // 清接收标志,准备下一字节
        }
    }
}
DEFINE_ISR(UART_Int, 0x28)  // 向量 0x28 对应 UART0 中断
{
    if (_rxif0)             // 如果收到新字节
    {
        recdata = _txr_rxr0; // 读取 RX 寄存器,同时硬件清 RXIF
    }
}

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐