一.实验目的
(1)熟悉 MCU 的异步串行通信 Uart 的工作原理。
(2)掌握 Uart 的通信编程方法。
(3)掌握中断的编程方法。
(4)掌握 PC 机的 C#串口通信编程方法。
二.实验内容
1.验证性实验
在光盘资料中 SD-KL-CD 提供读者串口通信实例 ch06-UART 文件夹中的 UART 程序主要实现开发板上的蓝灯闪烁、通过 MCU 串口发送字符串"change light"、回发接收数据。将光盘中的UART 程序下载至目标板,将USB转TTL串口线连接至开发板和电脑的USB口,打开串口调试工具或 ch06-UART 文件夹中的“C#2010 串口测试程序”进行串口通信测试,理解 main.c 程序和中断服务例程 isr.c。PC 机的 C#界面设计了发送文本框和接收字符型文本框、十进制型文本框、十六进制型文本框,理解接收、发送功能。
2.设计性实验
(1)修改光盘资料中 SD-KL-CD 提供读者串口通信实例 ch06-UART 文件夹中的 UART程序,实现通过串口调试工具或 ch06-UART 文件夹中的“C#2010 串口测试程序”发送字符’1’或者’0’来控制开发板上的蓝色 LED 灯,MCU 的 UART 接收到字符’1’时打开蓝色 LED灯,接收到字符’0’ 时关闭蓝色 LED 灯。
请在实验报告中给出 MCU 端程序 main.c 和 isr.c 流程图及程序语句。
(2)修改光盘资料中 SD-KL-CD 提供读者串口通信实例 ch06-UART 文件夹中的 UART程序,实现通过串口调试工具或 ch06-UART 文件夹中的“C#2010 串口测试程序”发送字符串’open’或者’close’来控制开发板上的蓝色 LED 灯,MCU 的 UART 接收到字符串’open’时打开蓝色 LED 灯,接收到字符串’ close’时关闭蓝色 LED 灯。
请在实验报告中给出 MCU 端程序 main.c 和 isr.c 流程图及程序语句。
3.进阶实验★
(1)利用光盘资料中 SD-KL-CD 提供读者串口通信实例 ch06-UART 文件夹中的 UART程序及其“C#2010 串口测试程序”,修改编写 MCU 方和 C#方程序,利用组帧方法来完成串口任意长度数据的接收和发送。实现 C#程序发送字符串’open’或者’close’来控制开发板上的蓝色 LED 灯,MCU 的 UART 接收到字符串’open’时打开蓝色 LED 灯,接收到字符串’ close’时关闭蓝色 LED 灯。
提示:组帧的双方约定“帧头+数据长度+有效数据+帧尾”为数值帧的格式,帧头和帧尾请自行设定。
请在实验报告中给出 MCU 端程序 main.c 和 isr.c 流程图及程序语句和 C#方主要程序段。
(2)利用上述实验中的组帧程序完成 C#方和 MCU 方程序功能,C#方程序实现鼠标点击不同按钮对应控制开发板上的三色灯完成相应颜色 LED 灯的显示。
请在实验报告中给出 MCU 端程序 main.c 和 isr.c 流程图及程序语句和 C#方主要程序段。
三.实验步骤和结果
1.验证性实验
将UART程序下载至目标板之后,蓝色小灯在闪烁,同时串口调试助手上接收到以下字符串:
经过对代码的分析可知第一行输出是程序通过串口2发送到串口的,其代码为:
uart_init(UART_2, 9600); //初始化串口2,波特率为9600;
uart_send_string(UART_2, "使用uart_send_string发送:Hello Uart_2!\r\n");
第二行及后续输出是由printf函数发送到串口的,由于printf函数内部将此函数所使用的串口号预先设置为串口2,所以在目标板连接串口2时可以接收到该输出。具体代码如下:
printf("使用printf函数发送:Hello Uart_2!\r\n");
printf("灯状态变换次数mLight_chang_num=%d\n",mLight_chang_num);
预先设置串口号的代码如下(printf内部):
#define UART_Debug UART_2 //printf函数使用的串口号
2.设计性实验
(1)通过串口输入1或0来控制蓝灯亮暗
思路分析:
- 通过串口调试工具向串口发送控制信号:1-小灯亮;0-小灯暗
- 注意:黑接GND,绿接RX,白接TX。
- 串口中断(UART2)接收到之后进行处理,判断,如果接收到的字符为’1’,则控制小灯亮,如果接收到的字符为’0’,则控制小灯暗
流程图(由于控制小灯亮暗的程序写在了串口中断函数中,故只写串口流程图,下同):
具体代码如下:
实验现象:
同要求一致。
(2)输入’open’和’close’来控制小灯的亮暗
思路分析:
- 本实验同前一个实验要求基本一直,故可将原实验中对1和0的判断改为对open和close的判断。我在这里使用了组帧的方式进行指令的发送。
- 组帧分析:第一位为帧头P 最后一位为帧尾C 第二位为发送数据的位数。
举例:发送open指令:P4openC ;发送close指令:P5closeC
- 首先向串口发送指令
- 如果数据部分为open则小灯亮;如果数据部分为close则小灯暗。
- 串口获取指令后,从buffer[2]开始,判断buffer[1]位数据。
流程图:
具体代码如下:
组帧程序:
//===========================================================================
//ISR名称:Createbuffer
//功能概要:组建数据帧,将待组帧数据加入到数据帧中
//参数说明:Data: 待组帧数据
// buffer: 数据帧变量
//函数返回:组帧状态 0-组帧未成功,1-组帧成功
//备注:十六进制数据帧格式
// 帧头 + 数据长度 + 有效数据 + 帧尾
// FrameHead + len + 有效数据 + FrameTail
//===========================================================================
uint8_t CreateFrame(uint8_t Data, uint8_t * buffer) {
static uint8_t frameCount = 0; //组帧计数器
uint8_t frameFlag; //组帧状态
frameFlag = 0; //组帧状态 初始化
//根据静态变量frameCount组帧
switch (frameCount) {
case 0: //第一个数据
{
if (Data == FrameHead) //收到数据是帧头FrameHead
{
buffer[0] = Data;
frameCount++;
frameFlag = 0; //组帧开始
}
break;
}
case 1: //第二个数据,该数据是随后接收的数据个数
{
buffer[1] = Data - '0';
frameCount++;
break;
}
default: //其他情况
{
//第二位数据是有效数据长度,根据它接收余下的数据直到帧尾前一位
if (frameCount >= 2 && frameCount <= (buffer[1] + 1)) {
buffer[frameCount] = Data;
frameCount++;
break;
}
//若是末尾数据则执行
if (frameCount >= (buffer[1] + 2)) {
if (Data == FrameTail) //若是帧尾
{
buffer[frameCount] = Data; //将帧尾0x44存入缓冲区
frameFlag = 1; //组帧成功
}
frameCount = 0; //计数清0,准备重新组帧
break;
}
}
} //switch_END
return frameFlag; //返回组帧状态
}
串口中断程序:
实验现象:
同要求一致。
3.进阶实验★
(1)使用组帧方式发送open和close控制小灯亮暗
由于设计实验的第二次实验已经使用open和close的组帧方式控制小灯亮暗,故不再赘述。
(2)利用组帧方式,在C#设计界面,用图形化的界面控制各种颜色小灯的亮暗。
思路分析:
- 在C#程序FormSCI上添加几个按钮,在每个按钮的响应事件中填写控制不同颜色小灯亮暗的程序
- 在对应颜色的按钮的响应事件中,将控制改颜色的编码用组帧的方式发送到串口
- 串口接收到之后,获取并比对控制数据,选择不同颜色的小灯进行操作。
流程图:
串口中断程序流程:
主函数控制流程:
C#界面设计:
具体代码如下:
C#各按钮响应事件实现程序:
//控制蓝灯
private void button1_Click(object sender, EventArgs e)
{
this.TbSCISend.Text = "P4blueC";
BtnSCISend_Click(sender, e);
}
//控制红灯
private void button2_Click(object sender, EventArgs e)
{
this.TbSCISend.Text = "P3redC";
BtnSCISend_Click(sender, e);
}
//控制绿灯
private void button3_Click(object sender, EventArgs e)
{
this.TbSCISend.Text = "P5greenC";
BtnSCISend_Click(sender, e);
}
//控制黄灯
private void button4_Click(object sender, EventArgs e)
{
this.TbSCISend.Text = "P6yellowC";
BtnSCISend_Click(sender, e);
}
//控制青色灯
private void button5_Click(object sender, EventArgs e)
{
this.TbSCISend.Text = "P6ngreenC";
BtnSCISend_Click(sender, e);
}
//控制紫色灯
private void button6_Click(object sender, EventArgs e)
{
this.TbSCISend.Text = "P6violetC";
BtnSCISend_Click(sender, e);
}
//控制白色灯
private void button7_Click(object sender, EventArgs e)
{
this.TbSCISend.Text = "P5whiteC";
BtnSCISend_Click(sender, e);
}
//关灯
private void button9_Click(object sender, EventArgs e)
{
this.TbSCISend.Text = "P5closeC";
BtnSCISend_Click(sender, e);
}
串口中断程序:
//串口1接收中断服务例程
void UART1_IRQHandler(void) {
uint_8 ch;
uint_8 flag;
DISABLE_INTERRUPTS; //关总中断
if (uart_get_re_int(UART_1)) {
ch = uart_re1(UART_1, &flag); //调用接收一个字节的函数,清接收中断位
if (flag) {
uart_send1(UART_1, ch); //向原串口发回一个字节
flagFrame = CreateFrame(ch, Buffer);
}
}
ENABLE_INTERRUPTS;
}
主函数控制程序:
if (flagFrame == 1) {//如果组帧成功
if (Buffer[2] == 'b' && Buffer[3] == 'l' && Buffer[4] == 'u'
&& Buffer[5] == 'e') {//蓝灯
light_control(LIGHT_BLUE, LIGHT_ON);
light_control(LIGHT_GREEN, LIGHT_OFF);
light_control(LIGHT_RED, LIGHT_OFF);
} else if (Buffer[2] == 'r' && Buffer[3] == 'e'
&& Buffer[4] == 'd') {//红灯
light_control(LIGHT_RED, LIGHT_ON);
light_control(LIGHT_GREEN, LIGHT_OFF);
light_control(LIGHT_BLUE, LIGHT_OFF);
} else if (Buffer[2] == 'g' && Buffer[3] == 'r' && Buffer[4] == 'e'
&& Buffer[5] == 'e' && Buffer[6] == 'n') {//绿灯
light_control(LIGHT_GREEN, LIGHT_ON);
light_control(LIGHT_BLUE, LIGHT_OFF);
light_control(LIGHT_RED, LIGHT_OFF);
} else if (Buffer[2] == 'y' && Buffer[3] == 'e' && Buffer[4] == 'l'
&& Buffer[5] == 'l' && Buffer[6] == 'o'
&& Buffer[7] == 'w') {//黄灯
light_control(LIGHT_GREEN, LIGHT_ON);
light_control(LIGHT_RED, LIGHT_ON);
light_control(LIGHT_BLUE, LIGHT_OFF);
} else if (Buffer[2] == 'n' && Buffer[3] == 'g' && Buffer[4] == 'r'
&& Buffer[5] == 'e' && Buffer[6] == 'e'
&& Buffer[7] == 'n') {//青灯
light_control(LIGHT_GREEN, LIGHT_ON);
light_control(LIGHT_RED, LIGHT_OFF);
light_control(LIGHT_BLUE, LIGHT_ON);
} else if (Buffer[2] == 'v' && Buffer[3] == 'i' && Buffer[4] == 'o'
&& Buffer[5] == 'l' && Buffer[6] == 'e'
&& Buffer[7] == 't') {//紫灯
light_control(LIGHT_GREEN, LIGHT_OFF);
light_control(LIGHT_RED, LIGHT_ON);
light_control(LIGHT_BLUE, LIGHT_ON);
} else if (Buffer[2] == 'w' && Buffer[3] == 'h' && Buffer[4] == 'i'
&& Buffer[5] == 't' && Buffer[6] == 'e') {//白灯
light_control(LIGHT_GREEN, LIGHT_ON);
light_control(LIGHT_RED, LIGHT_ON);
light_control(LIGHT_BLUE, LIGHT_ON);
} else if (Buffer[2] == 'c' && Buffer[3] == 'l' && Buffer[4] == 'o'
&& Buffer[5] == 's' && Buffer[6] == 'e') {//关灯
light_control(LIGHT_GREEN, LIGHT_OFF);
light_control(LIGHT_RED, LIGHT_OFF);
light_control(LIGHT_BLUE, LIGHT_OFF);
}
}
实验现象:
点击对应按钮,则对应颜色的小灯亮,点击关灯,则小灯暗。
四.实验总结(需加入心得体会)
通过本次实验,我熟悉了MCU异步通信Uart的工作原理、通信编程方法、中断的使用方法以及C#串口通信的方法,在实验的过程中还学到了C#程序的form编程,学会了如何使用和设置按钮。除此之外,我还了解了在传输过程中使用帧格式的重要性,以及对帧格式和组帧、解析方式都学到了很多。