当前课程知识点:ARM微控制器与嵌入式系统 > 第五章 ARM微控制器的各种外设 > E2 实验二 UART编程实操 > E2 实验二 UART编程实操
各位同学大家好
我是清华大学工程物理系的曾鸣老师
欢迎大家继续回到我们
ARM微控制器与嵌入式的MOOC课堂
那么在这个单元里呢
我们进行我们实验2的内容
实验2的内容就是跟我们前面衔接
进行uart异步串行通讯的实验
那么uart异步串行通讯
是一个知识点非常多的章节
我们几乎用了两周的时间
用了五六段视频
从它的原理
到它的小游戏
从它的实现到它怎么做这个寄存器的编程
讲了很多很多
但是万变不离其宗
我们自己来写个程序
做一个实验把它真正run起来
那么我们就真正掌握了这个章节
从任何一个嵌入式系统
或者一个生疏的MCU大家上手来讲
我们一般会认为你能点个灯
同时能实现一个串行通讯
你基本上就把这个硬件跑通了
那么剩下的内容你心里就不用怕了
所以我们来把我们手上这个KL25
这个ARMMCU真真正正给跑通起来在这个实验里
那么从这个实验内容来讲
我们做异步串行通讯先看看我们涉及到的知识点
一个是第五章 第二单元
我给大家讲的外设通讯
特别是异步串行通讯这一个章节的知识内容
他所涉及到的所有寄存器
在我们MKL25这样一个芯片手册里
它分布在第11章 第12章 第40章和第10章
其中呢 第11章是我们整个这个Port的
相关的这些引脚的介绍
第12章呢
是我们系统集成模块里头
对于这些引脚的定义和分配这样一种介绍
而真正uart这些寄存器
都在第40章里大家都可以找到
那么我们进行这个实验任务的时候
先从实验任务0开始讲起
我们要做一个串行通讯的这样一个实验
首先最重要一件事情就是把我们的电路
完整的连接起来
通过实验0和实验1
大家已经非常熟悉了我们的调试用的计算机
通过我们的OPENSDA
或者是称为Jlink的调试器
怎么通过USB以及调试线与我们那板子相连
那么在做通讯的时候
我们需要另外一个电路
就右边这根线我们的板子通过串行线
串行通讯线
或者是虚拟成USB的串行通讯
再与我们的计算机相连
计算机上通过一个叫超级终端
或者是串口调试助手这样的软件
与我们板子建立一个通讯的链接
这样我们在调试当中给板子写程序
板子通过通讯接口能够与计算机完成通讯
从而进行这样一个实验
那么在硬件连接上我们OPENSDA或者Jlink
就像这张图所示
大家注意这个调试线连接的正确性
这大家都很熟悉了
而我们的USB的虚拟串口的通讯
是因为我们板子上之前讲过
有一个虚拟串行通讯接口
它是我们板子正面看到的
两个USB通讯口当中标识为uart的下面这一个
上面那个口只取电
没有通讯功能
我们做本单元所做的实验的时候
大家给这个实验板的USB线
注意插在下面这个USB口
那么如果这个口插对了
我们也正确的安装了我们USB虚拟串口的
这个驱动程序以后
那么就像第0次实验给大家所说的
上电以后我们在我们计算机的设备管理器里
应该成功看到认出一个CP210x的虚拟串口
这个串口如果我们单机右键点击属性
还可以更改它的串口号
也就是我们待会在超级终端
或者大家自己喜欢用串口助手里头
所要打开那个串口的序号
这个要注意统一
那么在我们实验0里头
给大家体验了第0个任务
就是把一个老师给的这个开发板的测试程序
给引入到CodeWarrior
并且把它编译build成功
下载烧写到我们板子里运行起来
那么这个细节我在这里不再展开详细讲
我们回忆一下它的过程
就是这个程序运行起来以后
在板子上我们可以验证
所有的按键和灯的显示
而对于我们这个单元的实验
最重要的一个功能是
这个测试程序也包括了对于串行通讯接口的
一个测试功能
那么它工作在波特率9600
每次通讯发送8个比特的字节
没有奇偶校验位 停止位一位
也就是9600 8N1这样一种通讯模式下
所以这个程序大家作为我们这个单元
实验的一个任务0可以再做一遍
然后将这个程序烧写到大家的板子里
那么熟悉嵌入式开发的同学呢
你当然可以使用自己的串口助手啊这样的工具
设计成9600 8N1的方式进行通讯
打开与这个USB虚拟串口的串口号
一致的串口
那么如果不熟悉的同学
那么如果大家是使用的是windows
你可以使用一个叫做超级终端的程序
这个程序在WinXP以下的windows里头
是系统自带的
那么WinXP以上的版本里头
不再带有这个程序我们提供了下载
大家可以把它免费的下载下来
直接运行使用
那么在这个程序里我们可以新建一个串行通讯
这个串行通讯就像这个图上所指示这个界面
大家打开与刚才在设备管理器里
设置的对应的正确的串口号
并且把通讯的模式设成9600 8N1
大家特别注意这个N奇偶校验位和流量控制
都应该设成没有
那么点确定
就建立起来一个
通过这个USB虚拟串口
与我们板子之间通讯的界面
那么在超级终端这个程序里
我们板子发给计算机的所有的16进制的数
都会转换成其对应的ASCII码在屏幕里显示出来
而我们在这个窗口激活的时候
键盘上敲击的任何一个字母和按键
都会将其对应的ASCII码的16进制数
通过计算机的串口发给我们的微控制器开发板
这样帮助我们去进行本单元的实验内容
那么相应的
我们测试程序运行起来是什么效果的
就是如界面里这个效果
我们板子会不停的读取板子上
三维的运动加速度传感器的值
并且把它发送给我们的超级终端
于是我们在超级终端里就会看到
这一串一行每次三个值在不停的刷新
所以如果大家看到了这个值
就说明这个串口的从中断到超级终端
到打开的串口的号以及配置是正确的
我们就可以进行下面的实验了
那么如果是正确大家可以摇摇你的板子
看一看这三个轴的加速度的值是否在发生改变
那么这就是实验2里头
我们用来测试我们的数据通讯电路
是否调通的任务0
那我们接下来再来看我们一个个的任务
任务1
请大家编写一个程序
把一个完整的ASCII码表通过我们的串行接口
由我们的微控制器发给我们的计算机端
从而在超级终端里
把一个完整的ASCII码表显示出来
那么多一点提示呢
就是大家为了让它看的很整齐
你是不是能把你的程序
写成每发送16个字符换一行
于是得到的效果是应该在超级终端里
看到像这样一张图
那么这张图可以看到从0、1、2、3、4
一直到大小写的ABCD显示了完整的ASCII码表
那么这个任务我给大家一点提示
大家再来做一点点做编程开发
我们都学习过ASCII码表
ASCII码表其实最早是7位的
一共有128个值
除掉前面不方便显示的控制字符
后面绝大多数是一个16进制数
对应 或者说7比特对应
大约一个字节少一个比特对吧
一个字节的16进制数对应一个字符
那我们要在超级终端里看到字母A
我们实际上是通过我们的微控制器
从串口发送了一个0X41对应的16进制数对不对
那么这个16进制数在C语言里头
又是character类型变量的单引号的A
所以我们学C语言都知道单引号的A就是41
所以我们要发送一个完整的ASCII码表
就是要把这128个字符依次从微控制器发送出去
而发送这128字符大家想一想
是不是就是把这个128个16进制数依次发送啊
所以这个任务就变得非常简单
也就是我们把这样递增的数顺序的
从我们的串行通讯接口给发送出去
那么任务明确了以后
我们就会发现
接下来的问题就是如何有序的
把这些数或者这些单字符给发送出去呢
那么回忆一下
我们上一个单元里给大家讲这个编程
从串口完成一次通讯有三个步骤对吧
串行通讯接口的模块时钟打开
引脚配置成当串口用
对串口的寄存器进行编程完成串口的初始化
和数据的收发
在上一个单元里
曾老师最后给出了接收一个字符
和发送一个字符的通讯函数对不对
分别是Getchar和Putchar
这样两个函数原形和代码
留下了一道思考题
这道思考题是什么呢
思考题是如果大家自己写一个
串行通讯接口uart1的init初始化函数
应该怎么写
其实怎么写在上一节课里给大家讲了
包括把这个transmitter和receiver的开关打开
包括配置好通讯的数据结构
配置好通讯串口的波特率对不对
就是这么几句话
所以呢 我在这里给个例子
写出来的串口的初始化函数
应该是由刚才我所说的这几个语句组成
所以这样一个uart1的init函数写好了以后
应该在我们main函数里调用一次
之后每当我们要向外发送一个字节的时候
我们直接调用我们所写的Putchar函数
往外输出一个字节就可以了
而Putchar函数的结构
是每次发送前查询发送的状态寄存器那一位
是不是置位了
是不是空的
空就说明前一次发送结束
我们就可以写入一个新的字节
是不是能够编成流程啊
那么有了这两个武器
我们的实验逐步走向深入
考验大家的内容是能不能
把我们刚才的任务发送一个ASCII码表
转换成要做的事情
再转换成代码的实现
所以我们的任务变成了
如何把从00到127这样的
128个值从串口发送出去
那这件事情所有有C语言基础的同学
都应该想到
我做一个简简单单的for循环就行对吧
那么这个for循环要想做的漂亮
就像我们刚才提示的我们还要注意
在每16个字符的时候打入一个换行符
比如\n \r
使我们超级终端能够显示出一个完整的换行
那么做完了任务一
我希望大家是自己写出这个程序来加以实现
我再给大家布置任务二
那么任务二呢是说
那么我们每当在超级终端里
用键盘按下任何一个字符按键
那么由我们的微控制器
在收到计算机发来这个字符的ASCII码的时候
把ASCII码对应的这个字符串这个值
送回来在超级终端当中回显
我不知道这个意思大家听明白了
我给大家解构一下这个任务
让大家理解自己应该怎么做
比方说我们在键盘上
按下了一个小写的字母A
那么计算机向我们的微控制器发的是单字符A
也就是它对应的一个字节的16进制值0X61
而我们微控制器拿到这个0X61这个值以后
应该想办法回馈一个字符串
让我们的超级终端收到这么一个字符串
显示出来的是字符的0X6和1
大家明白这个任务没有
所以这个任务的执行效果
就如这张图所示每按一个字母后面一个杠
0X几几 它的ASCII码
有微控制器回答你
并且换行
然后等着你再输下一个字符
周而复始
所以这里头会有两个难点
一个是如何把一个收到的值变成字符串送回来
一个是如何实现这个任务所在这个机制
等人输入 显示 回车 换行
如果有良好C语言基础的同学
你会觉得这个任务非常简单
它只是把大家在计算机上做的程序的
输入输出函数改成了
我们微控制器的串行输入输出
大家仍然在main函数里编程
那么如果相应C语言基础差的同学
可以跟着我稍微看一看提示
那么我们正常情况下收到一个单字符的变量
单引号的M
这个单独引号的M实际上对应的
是它的一个ASCII码的值
这个ASCII码的值呢是0X6D
所以我们程序的任务就是要把这个0X6D
拆解成0X6和D这四个字符
送回给我们的计算机端
从微控制器的串行通讯口发送出去
那么核心任务0和X是固定的
就是如何得到6和D这个字符
大家说那我Putchar 6或者Putchar D不就可以了吗
那是人来做
我们要的是一个程序
是输入千变万化的字符
都能自动通过程序得到对应的
两个ASCII码的字符串对不对
就是要用程序来加以实现
那么我们想一想
我们拿到任何一个16进制的数
不管输入的值是多少
它反正就是两位16进制数
输出的字符是不是不外乎
0、1、2、3、4、5、6、7、8、9
和A、B、C、D、E、F这16个字符会出现
所以我们要解决的问题就是
如何把任意一个单位的0到15的值
对应成0到F这个字符
那么这个函数应该怎么写呢
我在这里直接给出了这个例子
那么因为这门课是一个微控制器的课
我就不花太多的时间去讲这里头
C语言的道理
只简单讲它的思想
就是我们判断我们现在拿到的这个
16进制这个数这两位
每一位单独拎出来处理对不对
低四位对应一个字符0到F
高四位对应一个字符0到F
所以一个8比特的这个字节拿到了以后
对应出来的是00到FF这样的组合
我们每次拿出一个字符来处理
它如果小于10或者小于等于9
也就是0到9之间的数
这个值加上单字符的0
就是字符的0到9对不对
那么如果它大于等于10它肯定不会大于16
也就是10到15
那么这个值减掉10剩下的差
加上单字符的字母A
就对应了字母A到F的字母
我们把得到的字母作为返回值
就把这个单位的数变成了一个字符
而如果我们对一个字节的
两位16进制数的高4位和低4位
分别做这样的编程
我们就顺利的得到了两个字符变量
那么剩下的程序如何形成一个流程
得到键盘输入的一个字符
这我们可以用之前老师给出的getchar函数
并且对它进行运算
正确的给出两个返回字符
然后我们让格式变得漂亮呢
我们应该前面加个杠
输出个0 输出个X
再输出这两个字符
再加一个换行符
所以考验大家事情是在main函数里头
把这些单元给用起来
让这个程序显得整洁和清晰
那么曾老师在这里给出了这个例程
但我更希望同学们现在先不仔细看这个例程
而是尝试在刚才提示下自己把它写出来
我们的拐棍会越来越少
后面的实验曾老师会逐渐不给例程
考验大家自己去完成
那我们看看任务三
任务三是本次实验最最有意思的一个任务
也是我们所有实验里
第一个开始特别好玩的任务
任务三是跟我们微控制器写一个程序
让我们能够跟我们微控制器
来进行一个猜数字的游戏
让我们微控制器我们MCU
每次自己生成一个0到9之间的随机数
然后将这个信息提示给我们的超级终端
通过串口发送出来
说guess my number
猜猜我的数
大家可以在键盘上
按从0到9当中的任何一个数
我们的微控制器可以返回Small or big
告诉你猜大了还是猜小了
然后经过若干轮次的猜测
直到我们自己输的数就是微控制器
等着你猜的那个随机数
它就会提示bingo
并且告诉你
你一共猜测了几次获得成功
就这么一个小游戏
那么类似的任务
可能大家在PC机在计算机上已经写过
那么难度就会低很多
我来给大家一点点提示
这样一个程序要实现
比我们刚才做的前两个任务又难了一点点
要注意什么呢
第一个难点
就是我们如何发送
一个字符串的提示信息对不对
比如是我们要发送一个字符串
叫guess my number
我们可以声明一个没有长度的字符串变量
这在C语言里头经常会使用
比如说unsigned char strHello
这样一个变量
那么它是双引号的hello感叹号
那么我们如何写一个sendstring的函数
用我们串行通讯的uart把它给发送出去呢
我给大家一点提示
在C语言里头字符串变量
最后一定有一个额外的看不见的字节
它的值是0X00对吧
所以我们可以从字符串的第一个值开始
用一个指针累加 逐一putchar每一个字符
直到读到一个值是00就停下来
所以这个函数写出来就是这样
它可以通用于各种字符串变量的输出
那么它的参数就是一个指向字符的指针
也就是字符串的名字
所以我们把函数声明成这样一个类型以后
我们就可以如下面这样
UART1_SendString括号一个字符串的名称
或者UART1_SendString直接双引号一个字符串
都可以灵活使用来在串口
输入任何我们要的信息
第二个难点我们如何产生一个随机数呢
那么很多同学学过计算机的编程都会说
我们include一个stdlib的头文件
我就可以用一个函数
这个函数叫rand
那么用这个rand函数呢
我就可以产生一个随机数
当然有的同学会说我会用Srand
带一个种子来产生随机数
为什么呢
因为技术好的同学就会说我用rand产生随机数
是一个固定序列
所以这个游戏每次玩的时候
第一次就猜这个值
第二次猜那个值
第三次就猜这个值
这个序列是固定的
所以我们已经学过我们要有一个Srand
要带个seed 带个种子
那大家回忆一下这个种子是什么
这个种子如果在计算机上
大家经常会取一个当前的时钟值
作为一个随机量
也就说这个随机数
它得根据一个真正的别的随机数来产生
这在我们微控制器上是不灵的
因为我们没有操作系统
没有那个获取时钟的函数对不对
那我们能怎么做
其实我们有一个非常简单的方法
我把代码在这里给出来
那么有兴趣的同学可以读一下这段代码
然后看一看我们在微控制器上
如何得到一个真随机数
那么这个做法比较巧
也就是说当我们给了提示信息的时候
我们实际上在for循环里
自己free running了一个累加的计数器
而当我们第一次猜测的时候这个计数器叫停
因为getchar函数得到了一个值
这个时候我们第一次猜测的时候
会使这个计数器当前的值是一个真随机数
它除以十的余数是我们真正要猜的值
而我们通过寄存器的检查
知道我们做了一个输入
并不影响我们后面用getchar函数
把这次输入的值仍然读出来
那么这样一个思想是比较巧妙的
那么建议大家仔细的去想一想
还有没有别的更好的方法
得到一个真随机数
我给一些提示
比如说我们板子上是有温度传感器的
我们板子上是有光线传感器的
这些传感器都是有噪声的
它的噪声最后一位都可以是随机的
那么最后一个难点
就我们程序的结构是什么样的
刚才提到这个随机数
我在这里给出了一个程序结构的伪代码
我们慢慢要锻炼一种能力
是在一个main函数里的框架里
老师给了很多函数
对这个硬件做了封装初始化
输出或者读取字符
我们如何自己能够慢慢锻炼编程能力
写出一个完整清晰的程序框架
再把它用C语言的方式加以实现
那么比如说我这里给了一个框架的例子
我们如何让这个程序周而复始
什么时候产生一个随机数
什么时候给提示
怎么得到人的输入信息
怎么反馈判断是大了是小了
给出不同的反馈乃至猜对了
那么这个框架大家要有
然后再用代码填进去把它写出来
所以本次实验的这个内容
我在这里建议大家停一下
根据框架或者你自己想出更好更清晰的框架
把代码自己写出来
然后再往下翻
看看老师给的例程跟你想的一不一样
你有没有更好的实现
那么老师给的例程我在这里也给出来
就是后面这个程序
那么大家可以自己想一想
你有没有更好的实现
如果你有更好更棒的方法
来完整的实现这么一个趣味的小游戏
那我们这次实验的目的就达到了
大家就真的把串口异步串行通讯给玩起来了
-1.1 课程概览
--1.1 课程概览
-1.2 如何学好嵌入式系统
-2.1 计算机的基本概念、发展历史
-2.2 从晶体管到CPU
-2.3 概念CPU、微控制器MCU和嵌入式系统
-2.4 八卦计算机史
-2.5 不同领域、不同系列的嵌入式系统
-2.6 ARM历史与MKL25Z128 MCU
--2.6 ARM历史与MKL25Z128 MCU【习题】
-3.1 CPU的基本结构和运行机制
-3.2.1 堆栈的概念
--3.2.1 堆栈的概念【习题】
-3.2.2 堆栈的概念-头脑体操
-3.3.1 ARM的体系结构
--3.3.1 ARM的体系结构【习题】
-3.3.2 ARM的体系结构-头脑体操
-3.4.1 中断的概念和机制
-3.4.2 中断子程的概念和编程
-3.5 复位、时钟、存储器和总线
--3.5 复位、时钟、存储器和总线【习题】
-3.6 小结:MCU的总体结构和程序运行机制
--3.6 小结:MCU的总体结构和程序运行机制【习题】
-4.1 第一种外设:IO
-4.2 IO外设的编程实操-点亮LED
-4.3 IO外设的进阶知识
-4.4 嵌入式开发的基本概念与工具链
-4.5 嵌入式开发的进阶知识
-4.6 嵌入式开发中的C语言(上)
--4.6 嵌入式开发中的C语言(上)【习题】
-4.7 嵌入式开发中的C语言(下)
--4.7 嵌入式开发中的C语言(下)【习题】
-E0.1 实验零 开发板的初步认识与工具链的安装
-E0.2 实验零 体验一个例程的编译与下载
-E0.3 实验零 编写第一个程序:点亮核心板LED
-E1 实验一 点灯秘籍
-5.1 ARM微控制器外设学习概述
-5.2.1 ARM微控制器外设:通讯
-5.2.2 ARM微控制器外设:异步串行通讯UART的原理(上)
--5.2.2 ARM微控制器外设:异步串行通讯UART的原理(上)
--5.2.2 ARM微控制器外设:异步串行通讯UART的原理(上)【习题】
-5.2.3 ARM微控制器外设:异步串行通讯UART的原理(下)
--5.2.3 ARM微控制器的外设:异步串行通讯UART的原理(下)
--5.2.3 ARM微控制器外设:异步串行通讯UART的原理(下)【习题】
-5.2.4 ARM微控制器外设:RS-232串口与USB虚拟串口
--5.2.4 ARM微控制器外设:RS-232串口与USB虚拟串口
-5.2.5 ARM微控制器外设:UART的寄存器编程(上)
--5.2.5 ARM微控制器外设:UART的寄存器编程(上)
-5.2.6 ARM微控制器外设:UART的寄存器编程(下)
--5.2.6 ARM微控制器外设:UART的寄存器编程(下)
--5.2.6 ARM微控制器外设:UART的寄存器编程(下)【习题】
-E2 实验二 UART编程实操
-5.3.1 ARM微控制器外设:IO的中断编程(上)
-5.3.2 ARM微控制器外设:IO的中断编程(下)
-5.4.1 ARM微控制器外设:定时器的原理
-5.4.2 ARM微控制器外设:定时器的编程
--5.4.2 ARM微控制器外设:定时器的编程【习题】
-E3 实验三 定时器中断编程实操
-5.5.1 ARM微控制器外设:PWM的原理
-5.5.2 ARM微控制器外设:PWM寄存器与编程
-5.5.3 ARM微控制器外设:PWM编程实例—电子音乐
--5.5.3 ARM微控制器外设:PWM编程实例—电子音乐
-E4 实验四 数码管显示编程实操
-5.6.1 ARM微控制器外设:SPI通讯简介
--5.6.1 ARM微控制器外设:SPI通讯简介【习题】
-5.6.2 ARM微控制器外设:SPI寄存器与编程
-5.6.3 ARM微控制器外设:SPI编程实例—OLED显示屏驱动
--5.6.3 ARM微控制器外设:SPI编程实例—OLED显示屏驱动
-5.7.1 ARM微控制器外设:I2C通讯简介
-5.7.2 ARM微控制器外设:I2C的通讯协议
-5.7.3 ARM微控制器外设:I2C寄存器与编程
--5.7.3 ARM微控制器外设:I2C寄存器与编程【习题】
-5.7.4 ARM微控制器外设:I2C编程实例—加速度传感器
--5.7.4 ARM微控制器外设:I2C编程实例—加速度传感器
-5.8.1 ARM微控制器外设:ADC简介
-5.8.2 ARM微控制器外设:ADC基础
-5.8.3 ARM微控制器外设:ADC寄存器与编程
-E5 实验五 ADC编程实操
-E6 挑战实验
--E6 挑战实验
-6.1 嵌入式系统的接口与设计
-6.2 嵌入式系统的实例