第四章Hanker TM4C123 外设应用
4.4 TM4C123 的串口通信
4.41 原理分析:
学过51 的同学都会知道串口通信。串口是计算机上一种非常通用设备通信的协议。大多数计算机包含两个基于RS232 的串口。串口同时也是仪器仪表设备通用的通信协议;很多GPIB 兼容的设备也带有RS-232 口。同时,串口通信协议也可以用于获取远程采集设备的数据。串口通信的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488 定义并行通行状态时,规定设备线总长不得超过20 米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200 米。典型地,串口用于ASCII 码字符的传输。通信使用3 根线完成:(1)地线,(2)发送,(3)接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但是不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。
对于两个进行通信的端口,这些参数必须匹配:
a,波特率:这是一个衡量通信速度的参数。它表示每秒钟传送的bit 的个数。例如300 波特表示每秒钟发送300 个bit。当我们提到时钟周期时,我们就是指波特率例如如果协议需要4800 波特率,那么时钟是4800Hz。这意味着串口通信在数据线上的采样率为4800Hz。通常电话线的波特率为14400,28800 和36600。波特率可以远远大于这些值,但是波特率和距离成反比。高波特率常常用于放置的很近的仪器间的通信,波特率除数(baud-rate divisor)是一个22 位数,它由16 位整数和6 位小数组成。波特率发生器使用这两个值组成的数字来决定位周期。通过带有小数波特率的除法器,在足够高的系统时钟速率下,UART 可以产生所有标准的波特率,而误差很小。
波特率除数公式:
BRD = BRDI.BRDF = SystemClock/(16×BaudRate)
其中:
BRD 是22 位的波特率除数,由16 位整数和6 位小数组成
BRDI 是BRD 的整数部分
BRDF 是BRD 的小数部分
SystemClock 是系统时钟(UART 模块的时钟直接来自SystemClock)
BaudRate 是波特率(9600,38400,115200 等)
b,数据位:这是衡量通信中实际数据位的参数。当计算机发送一个信息包,实际的数据不会是8 位的,标准的值是5、7 和8 位。如何设置取决于你想传送的信息。比如,标准的ASCII 码是0~127(7 位)。扩展的ASCII 码是0~255(8 位)。如果数据使用简单的文本(标准ASCII 码),那么每个数据包使用7 位数据。每个包是指一个字节,包括开始/停止位,数据位和奇偶校验位。由于实际数据位取决于通信协议的选取,术语“包”指任何通信的情况。
c,停止位:用于表示单个包的最后一位。典型的值为1,1.5 和2 位。由于数据是在传输线上定时的,并且每一个设备有其自己的时钟,很可能在通信中两台设备间出现了小小的不同步。因此停止位不仅仅是表示传输的结束,并且提供计算机校正时钟同步的机会。适用于停止位的位数越多,不同时钟同步的容忍程度越大,但是数据传输率同时也越慢。
d,奇偶校验位:在串口通信中一种简单的检错方式。有四种检错方式:偶、奇、高和低。当然没有校验位也是可以的。对于偶和奇校验的情况,串口会设置校验位(数据位后面的一位),用一个值确保传输的数据有偶个或者奇个逻辑高位。例如,如果数据是011,那么对于偶校验,校验位为0,保证逻辑高的位数是偶数个。如果是奇校验,校验位为1,这样就有3 个逻辑高位。高位和低位不真正的检查数据,简单置位逻辑高或者逻辑低校验。
图1 为UART 的外设模块图,可以看出,串口模块提供uDAM 通道,并且有16*8 的接收和发送缓冲。需要了解的就是串口对应的寄存器,比如控制与状态寄存器,中断控制寄存器等。
4.42 硬件设计:
几乎任何单片机或者是ARM 都有异步串口外设,学过51 单片机的通信都知道,一般串口都有两条线:RXD 和TXD。TM4C123 有八个UART 模块。大家可能觉得串口太多了吧,觉得没有用吧。其实不然,一工程师说到他的一个项目中,MUC 用到了九个串口,在一些特殊场合,这么多串口也是需要的。
Hanker-TM4C123 开发板抛弃了传统的串口输出,加入串口转USB,因为现在大家使用的笔记本已经无串行接口端。Silicon Laboratories 公司推出的USB 接口与RS232 接口转换器CP2102 是一款高度集成的USB-UART 桥接器,提供一个使用最小化元件和PCB 空间来实现RS232 转换USB 的简便解决方案。详细资料请参考相关datasheet.选择cp2102 之前,考虑过pl2303,但pl2303 不但外围器件多,在有干扰时很容易挂起出错,特别是提供的驱动程序在挂起后使电脑当机了,只有关掉电源,重新上电开机后才能恢复工作。而且CP2102 接口线路简单,电路如图2 所示:
硬件连接:PE4----------------U5RX
PE5----------------U5TX 串口多通道了,我们选择串口5,如何要选择其他
通道请去查找参考手册:14.2 Signal Description 内对管脚对应的串口有具体描述:
4.43 软件设计:.
那么首先我们建立工程项目如下图所示:
下面介绍下几个加入文件,其中lcd_320X240_ili932x.c 文件为液晶触摸屏的驱动文件,如果不使用液晶屏的话就可以不加入,要使用的时候还必须结合图形驱动库文件一起使用。
Main 函数就是我们用户编写的代码,由于我们使用了库函数编写,所以要加入外设驱动库封装.lib 文件,这里面封装了所有的外设驱动,下面我们在下面文件夹找到
ustdilb.c 文件是标准的串口输出函数库,这个是配合TI 的库专门写的。
Uartstdio.c 文件则是提供简单的串口控制功能,配合用户使用的。这两个文件都是串
口辅助文件。
driverlib/uart.C 查找下面几个要使用的函数:
1.UARTConfigSetExpClk( )功能:
UART 配置(要求提供明确的时钟速率)
原型
- void UARTConfigSetExpClk(unsigned long ulBase,
- unsigned long ulUARTClk,
- unsigned long ulBaud,
- unsigned long ulConfig)
复制代码参数
ulBase:UART 端口的基址,取值UART0_BASE、UART1_BASE 或UART2_BASE
ulUARTClk:提供给UART 模块的时钟速率,即系统时钟频率
ulBaud:期望设定的波特率
ulConfig:UART 端口的数据格式,取下列各组数值之间的“或运算”组合形式:
数据字长度
- UART_CONFIG_WLEN_8 // 8 位数据
- UART_CONFIG_WLEN_7 // 7 位数据
- UART_CONFIG_WLEN_6 // 6 位数据
- UART_CONFIG_WLEN_5 // 5 位数据
复制代码停止位
- UART_CONFIG_STOP_ONE // 1 个停止位
- UART_CONFIG_STOP_TWO // 2 个停止位(可降低误码率)
复制代码校验位
- UART_CONFIG_PAR_NONE // 无校验
- UART_CONFIG_PAR_EVEN // 偶校验
- UART_CONFIG_PAR_ODD // 奇校验
- UART_CONFIG_PAR_ONE // 校验位恒为1
- UART_CONFIG_PAR_ZERO // 校验位恒为0
复制代码 2.UARTConfigSet( )
功能
UART 配置(自动获取时钟速率)
原型
- #define UARTConfigSet(a, b, c) UARTConfigSetExpClk(a, SysCtlClockGet( ), b, c)
复制代码参数
详见上个函数描述
返回
无
说明
本宏函数常用来代替函数UARTConfigSetExpClk( ),在调用之前应当先调用SysCtlClockSet( )函数设置系统时钟(不要使用误差很大的内部振荡器IOSC、
IOSC/4、INT30 等)
示例
// 配置UART0:波特率9600,8 个数据位,1 个停止位,无校验
UARTConfigSet(UART0_BASE, 9600, UART_CONFIG_WLEN_8
|UART_CONFIG_STOP_ONE |
UART_CONFIG_PAR_NONE);
// 配置UART1:波特率最大,5 个数据位,1 个停止位,无校验
UARTConfigSet(UART1_BASE,SysCtlClockGet( )/ 16,UART_CONFIG_WLEN_5
|UART_CONFIG_STOP_ONE |UART_CONFIG_PAR_NONE);
3.UARTEnable( )
功能
使能指定UART 端口的发送和接收操作
原型
- void UARTEnable(unsigned long ulBase)
复制代码参数
ulBase:UART 端口的基址,取值UART0_BASE、UART1_BASE 或UART2_BASE
4.UARTCharPut( )
功能
发送1 个字符到指定的UART 端口(等待)
原型
- void UARTCharPut(unsigned long ulBase, unsigned char ucData)
复制代码参数
ulBase:UART 端口的基址,取值UART0_BASE、UART1_BASE 或UART2_BASE
ulData:要发送的字符
返回
无(在未发送完毕前不会返回)
5.UARTCharGet( )
功能
从指定的UART 端口接收1 个字符(等待)
原型
- long UARTCharGet(unsigned long ulBase)
复制代码参数
ulBase:UART 端口的基址,取值UART0_BASE、UART1_BASE 或UART2_BASE
返回
读取到的字符,并自动转换为long 型(在未收到字符之前会一直等待)
6.UARTCharPutNonBlocking( )
功能
发送1 个字符到指定的UART 端口(不等待)
原型
- tBoolean UARTCharPutNonBlocking(unsigned long ulBase, unsigned char ucData)
复制代码参数
ulBase:UART 端口的基址,取值UART0_BASE、UART1_BASE 或UART2_BASE
ulData:要发送的字符
返回
如果发送FIFO 里有可用空间,则将数据放入发送FIFO,并立即返回true
如果发送FIFO 里没有可用空间,则立即返回false(发送失败)
对于调用库函数编写串口程序一般可以归纳为如下步骤:
1. 使能串口外设所用到的GPIO 管脚
2. 使能串口外设
3. 配置管脚的复用功能
4. 配置串口时钟,串口波特率,等待位等
完成上面四个步骤,就可以用库函数配置为一个可用串口。
通常,在调用本函数之前应当先调用UARTSpaceAvail( )确认发送FIFO 里有可用空间
现在来实现PC 一个发送一个数据,串口接收,然后返回PC 的试验。程序如下:
这里面需要详细介绍下:
- 01. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- 02. //-----------------------------------------------------------------------------
- 03. // 文件名: uart.c
- 04. // 作者: 青风
- 05. // ARM 内核: Cortex-M4
- 06. // 使用芯片: LM4F232H5QD/TM4C
- 07. // 开发环境: KEIL
- 08. // 版本记录: V1.00 2011-12-26 14:30
- 09. // 功能说明:
- 10. //-----------------------------------------------------------------------------
- 11.
- 12.
- 13. #include "inc/hw_types.h" //定义常用的宏
- 14. #include "inc/hw_memmap.h" //定义功能存储映射
- 15. #include "grlib/grlib.h" //
- 16. #include "drivers/lcd_320x240_ili932x.h"
- 17. #include "driverlib/sysctl.h" //
- 18. #include "driverlib/gpio.h" //
- 19. #include "driverlib/sysctl.h"
- 20. #include "driverlib/uart.h"
- 21. #include "driverlib/pin_map.h" //
- 22. #include "driverlib/fpu.h" //
- 23. #include "inc/hw_ints.h" //定义中断分配数
- 24. #include "driverlib/interrupt.h" //
- 25. #include "utils/ustdlib.h"
- 26. #include "utils/uartstdio.h"
- 27.
- 28.
- 29. //-----------------------------------------------------------------------------
- 30. // 子函数功能说明: 串口功能设置
- 31. //-----------------------------------------------------------------------------
- 32. void
- 33. InitConsole(void)
- 34. {
- 35. SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); // 使能GPIO 外设
- 36. GPIOPinConfigure(GPIO_PE4_U5RX); // 配置串口接收管脚
- 37. GPIOPinConfigure(GPIO_PE5_U5TX); // 配置串口发送管脚
- 38. GPIOPinTypeUART(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);//把GPIO 功能复用为
- 串口
- 39. UARTStdioInit(5); //设置串口属性
- 40. }
- 41. //-----------------------------------------------------------------------------
- 42. // 主函数
- 43. //-----------------------------------------------------------------------------
- 44. int main(void)
- 45. { tContext sContext;
- 46. tRectangle sRect;
- 47. char cThisChar;
- 48. // char cText[10];
- 49. int x=10;
- 50. int y=10;
- 51. FPUEnable(); //FPU 使能
- 52. FPULazyStackingEnable(); //使能FPU 堆栈
- 53. SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
- 54. SYSCTL_XTAL_16MHZ); //系统时钟设置
- 55. InitConsole();
- 56. lcd_ili932x_init();
- 57. // GLCD_Test(); //初始化LCD 驱动
- 58. GrContextInit(&sContext, &g_sLcdDisplay);//初始化图形库
- 59. lcd_backlight_on();
- 60. lcd_ili932x_flush(&sContext);
- 61. sRect.sXMin = 0;
- 62. sRect.sYMin = 0;
- 63. sRect.sXMax = GrContextDpyWidthGet(&sContext) - 1;
- 64. sRect.sYMax = 23;
- 65. GrContextForegroundSet(&sContext, ClrDarkBlue);
- 66. GrRectFill(&sContext, &sRect); // 填充蓝色方块
- 67. GrContextForegroundSet(&sContext, ClrWhite);
- 68. GrRectDraw(&sContext, &sRect); // 加白色框框
- 69. GrContextFontSet(&sContext, &g_sFontCm20);
- 70. GrStringDrawCentered(&sContext, "UART", -1,
- 71. GrContextDpyWidthGet(&sContext) / 2, 10, 0); // 显示串口实验标志
- 72. UARTprintf("start"); // 串口显示
- 73. GrContextFontSet(&sContext, &g_sFontCm20); //
- 74. GrStringDraw(&sContext, "start", -1, 50, 50, 1);// TFT 显示
- 75. while((x+y)<320) //
- 76. { y=y+x;
- 77. cThisChar = UARTCharGet(UART5_BASE); //
- 78. UARTCharPut(UART5_BASE, cThisChar); //
- 79. GrContextFontSet(&sContext, &g_sFontCm20);//
- 80. GrStringDraw(&sContext, &cThisChar, -1, y, 80, 1); //打印信息
- 81. }
- 82. return(0);
- 83. }
- 84.
复制代码下载成功后出现下面现象:
打开串口调制助手,设置如下:
下载成功后:串口输入一句:QFV5.taobao.com.发送后回环接收。