环境介绍
Keil : 版本5.34.0.0 编译器V6
官方SDK版本:Nuvoton.NuMicro_DFP.1.3.12
RT_THREAD -3.15 nano 请在KEil 的Run-Time Environment环境进行下载, 需要自行实现systick定时器的中断定时器功能
外设硬件特性
该芯片提供6路通用异步接收/发送(UART)。UART控制器执行正常速度UART,支持流量控制功能。UART控制器对从外设接收的数据执行串行到并行的转换,并对从CPU传输的数据执行并行到串行的转换。每个UART控制器通道支持十种类型的中断。UART控制器还支持IrDA SIR、LIN和RS-485功能模式和autobaud速率测量功能。
M23554的串口比ST的芯片多了一些高级的功能,
带有16个字节的 缓冲区,减少CPU干预时间,
自动波特率,波特率补偿功能
支持RS485
自动流控制
例程功能介绍
电脑发送0x01 绿灯亮,并返串口回灯状态信息
电脑发送0x02 绿灯灭,并返串口回灯状态信息
把接收到字符返回,没有做FIFO溢出检查,所以一次不能超16字节,否则丢包,只做演示。
硬件配置:
使能时钟
确认外设时钟源,以及频率,设置预分频器。
设置工作模式 ,以及波特率
配置引脚
设置传输数据参数
收发功能寄存器是默认使能的
时钟源可以选项,和操作函数CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL2_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
波特率的设置依据
我们要求的是115200;
外设频率已经是12MHZ,设置模式2, UART_BAUD.BRD = 102 UART_BAUD.EDIVM1 = 0
波特率 = 12000 000/(102+2) = 115,384
设置模式1, UART_BAUD.BRD = 6 UART_BAUD.EDIVM1 = 12
波特率 = 12000 000/(12+1)*(6+2) = 115,384
当然实际SDK提供相关的函数可以直接调用,这样做是熟悉相关产平线的外设特性。查看代码却只发现有模式0 和模式2的宏定义,自行测试模式1的配置运行ok.
配置数据格式的是寄存 UART_LINE
UART0->LINE = UART_PARITY_NONE | UART_STOP_BIT_1 | UART_WORD_LEN_8;
波特率补偿:
我们发现我们计算的波特率是有误差的,当然很小的时候是可以容错的,当时过大就需要补偿了,CAN通信这么稳,就有这个机制存在
那手册上的例子分析一下
UART 的外设时钟 = 32.768 kHz,波特率为 9600 bps,我们需要设置相关的 参数让他的波特率等于9600,
32.768 kHz / 9600 hz = 3.413 ,因为设置的参数只能是整数(stm32支持分数波特率计算),我们最后就得到了每周期0.413 个时钟的偏差。
矫正寄存器 UART_BRCOMP 详细功能看查看手册
BRCOMPDEC (UART_BRCOMP[31]) = 0,为每一位正补偿,多一位模块时钟将附加在补偿位中。如BRCOMPDEC (UART_BRCOMP[31]) = 1,则为每一位负补偿,补偿位减少一个模块时钟。
工作原理:
发送:
通过向寄存器写入一个字节,数据字节将存储在发送器FIFO中。UART控制器将通过UART_TXD发送存储在发送器FIFO顶部位置的数据。再由移位寄存器发出
XEMPTYF (UART_FIFOSTS [28]) TX FIFO (UART_DAT) 是否为空
TXOVIF(UART_FIFOSTS [24]) TX FIFO 是否溢出检查 可生成中断
TXFULL(UART_FIFOSTS [23]) TX FIFO是否满了
TXEMPTY(UART_FIFOSTS [22]) TX FIFO是否为空
TXPTR(UART_FIFOSTS [22]) TX FIFO当前位置指针
接收:
接收到的数据存入接收FIFO,通过读 UART_DAT 取这个寄存器,UART控制器将从接收器FIFO返回一个8位数据。
当RX FIFO中的字节数等于RFITL(UART_FIFO[7:4])时,将设置RDAIF(UART_INTSTS[0])。
如果启用了RDAIEN (UART_INTEN[0]),则会产生RDA中断。
注意:该位是只读的,当RX FIFO的未读字节数低于阈值水平(RFITL(UART_FIFO[7:4])时,该位将被清除。
UART_FUNCSEL 寄存器进行外设的工作模式的选着以及
对应的接收FIFO的信息更多再 UART_FIFO ,重要的有RFITL(UART_FIFO[7:4]),接收收到个数触发中断阈值设置
如果接收或者发送快速的话就需要是由中断或者DMA进行收发了。
代码:
初始化函数:
void UART0_Init(void)
{
//配置步骤6.19.4 Basic Configuration TRM_M2354_Series_EN_Rev1.01
CLK_EnableModuleClock(UART0_MODULE);
CLK_SetModuleClock(UART0_MODULE, CLK_CLKSEL2_UART0SEL_HIRC, CLK_CLKDIV0_UART0(1));
SYS->GPA_MFPL = (SYS->GPA_MFPL & (~(UART0_RXD_PA6_Msk | UART0_TXD_PA7_Msk))) | UART0_RXD_PA6 | UART0_TXD_PA7;
UART0->LINE = UART_PARITY_NONE | UART_STOP_BIT_1 | UART_WORD_LEN_8;
UART0->BAUD = UART_BAUD_MODE2 | UART_BAUD_MODE2_DIVIDER(__HIRC, 115200);
}
应用线程:
//SDK 有发送数据包的函数
static void rt_led_thread_entry(void* parameter)
{
uint8_t u8InChar = 0xFF;
uint8_t butter =0;
while(1)
{
if(UART0->INTSTS &0x00000001) //RX FIFO 收到预设数(1个)量数据
{
butter = (uint8_t)UART_READ(UART0);
UART_WRITE(UART0, butter);
printf("接收到的数据 = %d\n",butter);
if(butter == 0x01) //亮
{
LED_GREEN = 0;
printf("亮灯 \n");
}
else if(butter == 0x02)//灭
{
LED_GREEN = 1;
printf("灭灯 \n");
}
else
{
}
}
rt_thread_delay(10);
}
}
这个做的有点坎坷,板载调试器再使用过程中,出现串口不能正常工作的情况,接收数据,怀疑自己的代码有问题,主控发热?!,自己外接一个串口测试。
原作者:wenkit