嵌入式技术基础与实践-学习札记(二)
异步串行通信的通用基础知识
串口通信接口,简称“串口”、\(UART\)或\(SCI\)。\(MCU\)中的串口通信,在硬件上分为发送线\((TxD)\)、接受线\((RxD)\)和地线\((GND)\);在通信方式上,属于单字节通信,是嵌入式开发中重要的打桩调试手段。
串行通信的基本概念
“位”\((bit)\)是单个二进制数字的简称。在计算机中,通常一个信息单位用\(8\)位二进制表示,成为一个“字节”\((Byte)\)。
串行通信的特点是:数据以字节为单位、按位的顺序(例如最高位优先)从一条传输线上发送出去。
异步串行通信的格式
空闲状态为"\(1\)",发送器通过发送一个“\(0\)“表示一个字节传输的开始,随后是数据位(在\(MCU\)中一般是\(8\)位或\(9\)位,可以包含校验位)。最后,发送器发送“\(1\)“表示一个字节传送结束。
串行通信的波特率
位长(\(Bit\ Length\)),也称为位的持续时间,其倒数就是单位时间内传送的位数。也就是波特率。单位是:位/秒,记为\(bps\)(\(bit\ per\ second\))。
奇偶校验
在异步串行通信中,通过增加一个奇偶校验位来判断一个字节传输是否正确。例如若采用奇校验,则增加一位记录字节中\(1\)是奇数个还是偶数个。
串行通信传输方式术语
- 全双工\((Full-duplex)\):数据传输是双向的,即可以同时接受与发送数据。
- 半双工\((Half-duplex)\):数据传输也是双向的,但在任何时刻,只能由一方发送数据,一方接受数据,不能同时收发。
- 单工\((Simplex)\):数据传送是单向的,一端位发送端,另一端为接受端。
串行通信编程模型
从基本原理角度看,\(UART\)的主要功能是:接受时,把外部的单线输入的数据变成一个字节的并行数据送入\(MCU\)内部;发送时,把需要发送的一个字节的并行数据转换为单线输出。
\(UART\)具有波特率寄存器,用于设置波特率。有控制寄存器,用于设置通信格式、是否校验、是否允许中断等。有状态寄存器,用于查询是否有数据可收、数据是否发送出去等。
ARM Cortex-M0+中断机制
关于中断的通用基础知识
中断:来自\(CPU\)外围设备的强行任务切换称为中断。
异常:是指硬件产生的复位和中断。
中断源:可以引起\(CPU\)产生中断的外部器件被称为中断源。
中断向量地址:每个中断源产生中断后,分别要运行相应的中断服务例程(\(Interrupt\ Service\ Routine)\),这些\(ISR\)的起始地址称为中断向量地址。
中断向量表:中断向量地址存放在一块连续的区域,这个存储区被称为中断向量表。
中断向量号:给中断源的编号。如果一个设备可以产生多个不同的中断,则允许有多个中断向量号。
中断处理的基本过程为中断请求、中断检测、中断响应与中断处理等。当某一中断源需要\(CPU\)为其服务时,它向\(CPU\)发出中断请求信号,中断控制器获取硬件设备的中断向量号,通过中断向量号获取中断状态寄存器的“中断请求位”,以便\(CPU\)知道何种中断请求。
M0+非内核模块中断编程结构
非内核中断请求\((Interrupt\ Request)\)号,简称\(IRQ\)中断号,从\(0\sim 31\)编号,对应中断向量号的\(16\sim 47\)。
M0+中断结构及中断过程
\(M0+\)中断结构由\(M0+\)内核、嵌套中断向量控制器\(NVIC\)及模块中断源组成。其中断过程分为两步:
- 模块中断源向嵌套中断向量控制器\(NVIC\)发出中断请求信号;
- \(NVIC\)对发来的中断信号进行判断是否中断使能,若使能,则通过私有外设总线\(PPB\)发送给\(M0+\)内核进行中断处理。如果同时有多个中断信号,则\(NVIC\)根据设置好的优先级进行判断响应。
M0+嵌套中断向量控制寄存器NVIC内部寄存器简介
\(NVIC\)内含\(12\)个寄存器。
- 中断使能寄存器\((NVIC\_ISER)\):中断使能寄存器的\(32\)位分别对应\(32\)个外设中断\(IRQ\)中断号。写\(1\)使能相应\(IRQ\)号中断,写\(0\)无效。
- 中断禁止寄存器\((NVIC\_ICER)\):中断禁止寄存器的\(32\)位分别对应\(32\)个外设中断\(IRQ\)中断号。写\(1\)禁止相应\(IRQ\)号中断,写\(0\)无效。
- 挂起/清除寄存器\((NVIC\_ISPR/NVIC\_ICPR)\):当中断发生时,正在处理高优先级中断,或该中断被屏蔽时,此时中断被挂起。中断的挂起可以通过中断挂起寄存器和清除挂起寄存器来读取,还可以通过写这些寄存器进行挂起中断。清除挂起表示取消此次中断请求。
- 优先级寄存器\((NVIC\_IPR0-NVIC\_IPR7)\):可以通过设置优先级寄存器设置非内核中断源的优先级。优先级寄存器\((Interrupt\ Priority\ Register,\ IPR)\)共有\(8\)个;\(IPR0\sim IPR7\),每个优先级寄存器对应\(4\)非内核中断源。由于每个优先级寄存器只控制\(4\)个非内核中断源,因此每个中断源在\(IPR\)寄存器中占两位,其他位未占用。
非内核中断初始化设置步骤
- 设置相应模块中断使能位使能中断。
- 查找芯片中断源表,找到对应中断请求\(IRQ\)号,根据\(IRQ\)号对应中断向量号,然后设置嵌套中断向量控制寄存器的中断使能寄存器或中断禁止寄存器,使该中断对应位置为\(1\)即可。
- 若要设置优先级则可对优先级寄存器编程。
UART驱动构件的设计方法
UART模块编程结构
\(KL25\)芯片有三个\(UART\)模块,每个模块有对应的寄存器。如控制寄存器,状态寄存器,波特率寄存器,数据寄存器。三个\(UART\)模块都有两个波特率寄存器,四个控制寄存器,两个状态寄存器和一个数据寄存器。其中\(UART0\)多出一个控制寄存器和两个地址匹配\(MA\)寄存器。
\(UART\)模块\(x\)的寄存器地址\(=4006\_A000+x\times 1000+n\times 1\)\((x=0\sim 2\);模块\(0\)中\(n=0\sim B\),模块\(1、2\)中\(n=0\sim 8)\),\(n\)表示寄存器号。
UARTx控制寄存器2(UARTx_C2)
主要用于收/发相关中断控制设置。
- \(D7(TIE)\)——发送中断使能位。与状态寄存器中的\(TDRE\)配合使用。\(TIE=0\),发送中断禁用(使用轮询);\(TIE=1\),当\(TDRE=1\)时,发生中断请求。
- \(D6(TCIE)\)——发送完成中断使能位,与状态寄存器中\(TC\)位配合使用。\(TCIE=0\),\(TC\)对应的中断禁用(使用轮询);\(TCIE=1\),当\(TC=1\)时,发生中断请求。
- \(D5(RIE)\)——接受中断使能位。与状态寄存器中的\(RDRF\)配合使用。\(RIE=0\),\(RDRF\)中断禁止(使用轮询);\(RIE=1\),当\(RDRF=1\)时,发生中断请求。
- \(D4(ILIE)\)——空闲线中断使能,与状态寄存器中的\(IDLE\)配合使用。\(ILIE=0\),\(IDLE\)中断禁止(使用轮询);\(RIE=1\),当\(IDLE=1\)时,发生中断请求。
- \(D3(TE)\)——发射器使能位。\(TE\)必须是\(1\)来使用\(UART\)发送器。通常在\(TE=1\)时,\(UART\_TX\)引脚作为\(UART\)系统的输出。当\(UART\)配置w诶单线模式\((LOOPS=1,RSRC=1)\)时,\(UART\_C3\)中的\(TXDIR\)位将控制单线模式下\(UART\_TX\)引脚的通信方向。
- \(D2(RE)\)——接收器使能。当\(UART\)接收器关闭或\(LOOPS\)被置位,\(UART\)不使用\(UART\_RX\)脚。\(RE=0\)接收器禁止,\(RE=1\)接收器使能。
- \(D1(RWU)\)——接收器唤醒控制位。\(RWU=0\),正常\(UART\)接收器操作;\(RWU=1\),接收器等待唤醒条件。唤醒方式有空闲线唤醒\((WAKE=0)\)和地址位唤醒\((WAKE=1)\)。
- \(D0(SBK)\)——发送中止使能位。\(SBK=0\),正常发送操作;\(SBK=1\),队列中止字符发送。
UARTx控制寄存器1(UARTx_C1)
主要用于设置\(SCI\)的工作方式,可选择运行模式,唤醒模式,空闲类型检测以及奇偶校验等。
UARTx状态寄存器1(UARTx_S1)
为\(UART\)中断或\(DMA\)请求提供\(MCU\)输入。可通过读取状态寄存器之后读和写\(UART\)数据寄存器来清除标志。
- \(D7(TDRE)\)——发送数据寄存器空标志位。\(TDRE=0\),发送数据寄存器已满;\(TDRE=1\),发送数据寄存器为空。
- \(D6(TC)\)——发送完成标志位。\(TC=0\),正在发送。\(TC=1\),发送完成。
- \(D5(RDRF)\)——接收数据寄存器已满标志位。\(RDRF=0\),接收数据寄存器空,\(RDRF=1\),接收数据寄存器满。为清除\(RDRF\)应先对该位读操作,然后读\(RART\)数据寄存器。
波特率寄存器:UARTx_BDH、UARTx_BDL
两个寄存器一同控制着波特率生成器的分频因子。
数据寄存器
\(UARTx\_D(x=0\sim 2)\)其实是两个单独的\(8\)位寄存器,读时会返回只读接收数据寄存器中的内容,写时会写到只写发送数据寄存器。