本篇文章由 VeriMake 旧版论坛中备份出的原帖的 Markdown 源码生成
原帖标题为:以 CH549 为例的 51 教程 | 图文 5. 通信:UART 和 SPI(上)
原帖网址为:https://verimake.com/topics/260 (旧版论坛网址,已失效)
原帖作者为:Xy(旧版论坛 id = 73,注册于 2020-10-15 13:03:26)
原帖由作者初次发表于 2021-08-19 15:39:44
📇 点此回到教程主索引
目录
串口通信介绍
串口通信具体代码解析
USB 转 TTL 模块与串口调试助手的使用方法
实验现象
串口通信介绍
串口通信,通常称作UART,是一种串行、异步、全双工的通信协议。

简单点说:串口通信有两根线,一条通信输出线,一条通信接受线,可以同时接受信息和输出信息。

什么是波特率
波特率指的每秒钟传送的码元符号的个数,是度量信息传输速度的单位,使用者需要保证串口接受端和输出端的波特率一致。
串口通信具体代码解析
main.c
/**
******************************************************************
* @file main.c
* @author xy
* @version V1.0
* @date 2021-3-31
* @brief 串口通讯
******************************************************************
* @attention
* verimake 用于ch549例程
* CH549 串口1~3 查询与中断收发演示,实现数据回环
* 注意包含CH549_DEBUG.C
******************************************************************
*/
#include <CH549_sdcc.h> //ch549的头文件,其中定义了单片机的一些特殊功能寄存器
#include <CH549_UART.h> //CH549官方提供库的头文件,定义了一些关于pwm初始化,设置等函数
#include <CH549_DEBUG.h> //CH549官方提供库的头文件,定义了一些关于主频,延时,串口设置,看门口,赋值设置等基础函数
/********************************************************************
* TIPS:
* 引脚 功能
* P2.6 默认UART1——RXD1
* P2.7 默认UART1——TXD1
* P1.6 UART1引脚映射————RXD1_
* P1.7 UART1引脚映射————TXD1_
* P0.4 UART2——RXD2
* P0.5 UART2——TXD2
* P0.6 UART3——RXD3
* P0.7 UART3——TXD3
*********************************************************************/
void main( )
{
UINT8 dat;
CfgFsys( ); //CH549时钟选择配置
mDelaymS(20);
CH549UART1Init(); //串口1初始化
CH549UART1Alter();
//串口1引脚映射-将串口一映射到 p1.6 和 p1.7 P1.6(UART1引脚映射————RXD1_)(P1.7 UART1引脚映射————TXD1_)
CH549UART2Init(); //串口2初始化
CH549UART3Init(); //串口3初始化
printf("hello world\n"); //串口输出:“hello world”
while(1);
}
/********************************************************************
* 函 数 名 : putchar
* 函数功能 : 将printf映射到串口通讯
* 输 入 : 字符串
* 输 出 : 字符串
********************************************************************/
int putchar( int a)
{
CH549UART1SendByte(a); //printf映射到串口1输出
return(a);
}
与PWM代码一致,调用的是沁恒官方提供的库,因此main函数中的内容简洁,便于理解。
代码的重要部分
putchar函数
/********************************************************************
* 函 数 名 : putchar
* 函数功能 : 将printf映射到串口通讯
* 输 入 : 字符串
* 输 出 : 字符串
********************************************************************/
int putchar( int a)
{
CH549UART1SendByte(a); //printf映射到串口1输出
return(a);
}
通过putchar函数将printf的输出方式改变为使用串口1来输出数据。
CH549_UART.c
、/********************************** (C) COPYRIGHT *******************************
* File Name : 官方uart库
* Author : WCH
* Version : V1.0
* Date : 2018/08/09
* Description : CH549 串口初始化相关
*******************************************************************************/
#include <CH549_UART.h>
#include <CH549_sdcc.h> //ch549的头文件,其中定义了单片机的一些特殊功能寄存器
/*******************************************************************************
* Function Name : CH549UART1Init
* Description : UART1初始化函数,串口默认引脚 P26 P27
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CH549UART1Init()
{
SCON1 &= ~bU1SM0; //选择8位数据通讯
SCON1 |= bU1SMOD; //快速模式
SCON1 |= bU1REN; //使能接收
SBAUD1 = 0 - FREQ_SYS/16/UART1_BUAD; //波特率配置
SIF1 = bU1TI; //清空发送完成标志
#ifdef UART1_INTERRUPT //开启中断使能
IE_UART1 = 1;
EA = 1;
#endif
}
/*******************************************************************************
* Function Name : CH549UART1Alter()
* Description : CH549串口1引脚映射,串口映射到 P16 P17
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CH549UART1Alter()
{
P1_MOD_OC |= (3<<6); //准双向模式
P1_DIR_PU |= (3<<6);
PIN_FUNC |= bUART1_PIN_X; //开启引脚复用功能
}
/*******************************************************************************
* Function Name : CH549UART1RcvByte()
* Description : CH549UART1接收一个字节
* Input : None
* Output : None
* Return : SBUF
*******************************************************************************/
UINT8 CH549UART1RcvByte( )
{
while((SIF1&bU1RI) == 0)
{
; //查询接收
}
SIF1 = bU1RI; //清除接收中断
return SBUF1;
}
/*******************************************************************************
* Function Name : CH549UART1SendByte(UINT8 SendDat)
* Description : CH549UART1发送一个字节
* Input : UINT8 SendDat;要发送的数据
* Output : None
* Return : None
*******************************************************************************/
void CH549UART1SendByte(UINT8 SendDat)
{
SBUF1 = SendDat;
while((SIF1&bU1TI) == 0)
{
; //查询等待发送完成
}
SIF1 = bU1TI; //清除发送完成中断
}
#ifdef UART1_INTERRUPT
/*******************************************************************************
* Function Name : UART1Interrupt(void)
* Description : UART1 中断服务程序
*******************************************************************************/
void UART1Interrupt(void) __interrupt INT_NO_UART1 __using 1 //串口1中断服务程序,使用寄存器组1
{
UINT8 dat;
if(SIF1&bU1RI)
{
SIF1 = bU1RI; //清除接收完中断
dat = SBUF1;
CH549UART1SendByte(dat);
}
}
#endif
/*******************************************************************************
* Function Name : CH549UART2Init
* Description : UART2初始化函数,串口默认引脚 P04 P05
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CH549UART2Init()
{
SCON2 &= ~bU2SM0; //选择8位数据通讯
SCON2 |= bU2SMOD; //快速模式
SCON2 |= bU2REN; //使能接收
SBAUD2 = 0 - FREQ_SYS/16/UART2_BUAD; //波特率配置
SIF2 = bU2TI; //清空发送完成标志
#ifdef UART2_INTERRUPT //开启中断使能
SCON2 |= bU2IE; //开启UART2中断,关闭ADC中断
IE_UART2 = 1;
EA = 1;
#endif
}
/*******************************************************************************
* Function Name : CH549UART2RcvByte()
* Description : CH549UART2接收一个字节
* Input : None
* Output : None
* Return : SBUF
*******************************************************************************/
UINT8 CH549UART2RcvByte( )
{
while((SIF2&bU2RI) == 0)
{
; //查询接收
}
SIF2 = bU2RI; //清除接收中断
return SBUF2;
}
/*******************************************************************************
* Function Name : CH549UART2SendByte(UINT8 SendDat)
* Description : CH549UART2发送一个字节
* Input : UINT8 SendDat;要发送的数据
* Output : None
* Return : None
*******************************************************************************/
void CH549UART2SendByte(UINT8 SendDat)
{
SBUF2 = SendDat;
while((SIF2&bU2TI) == 0)
{
; //查询等待发送完成
}
SIF2 = bU2TI; //清除发送完成中断
}
#ifdef UART2_INTERRUPT
/*******************************************************************************
* Function Name : UART1Interrupt(void)
* Description : UART1 中断服务程序
*******************************************************************************/
void UART2Interrupt( void ) __interrupt INT_NO_UART2 __using 1 //串口2中断服务程序,使用寄存器组1
{
UINT8 dat;
if(SIF2&bU2RI)
{
SIF2 = bU2RI; //清除接收完中断
dat = SBUF2;
CH549UART2SendByte(dat);
}
}
#endif
/*******************************************************************************
* Function Name : CH549UART3Init
* Description : UART3初始化函数,串口默认引脚 P06 P07
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void CH549UART3Init()
{
SCON3 &= ~bU3SM0; //选择8位数据通讯
SCON3 |= bU3SMOD; //快速模式
SCON3 |= bU3REN; //使能接收
SBAUD3 = 0 - FREQ_SYS/16/UART3_BUAD; //波特率配置
SIF3 = bU3TI; //清空发送完成标志
#ifdef UART3_INTERRUPT //开启中断使能
SCON3 |= bU3IE; //开启UART3中断,关闭PWM中断
IE_UART3 = 1;
EA = 1;
#endif
}
/*******************************************************************************
* Function Name : CH549UART3RcvByte()
* Description : CH549UART3接收一个字节
* Input : None
* Output : None
* Return : SBUF
*******************************************************************************/
UINT8 CH549UART3RcvByte( )
{
while((SIF3&bU3RI) == 0)
{
; //查询接收
}
SIF3 = bU3RI; //清除接收中断
return SBUF3;
}
/*******************************************************************************
* Function Name : CH549UART3SendByte(UINT8 SendDat)
* Description : CH549UART3发送一个字节
* Input : UINT8 SendDat;要发送的数据
* Output : None
* Return : None
*******************************************************************************/
void CH549UART3SendByte(UINT8 SendDat)
{
SBUF3 = SendDat;
while((SIF3&bU3TI) == 0)
{
; //查询等待发送完成
}
SIF3 = bU3TI; //清除发送完成中断
}
#ifdef UART3_INTERRUPT
/*******************************************************************************
* Function Name : UART1Interrupt(void)
* Description : UART1 中断服务程序
*******************************************************************************/
void UART3Interrupt( void ) __interrupt INT_NO_UART3 __using 1 //串口3中断服务程序,使用寄存器组1
{
UINT8 dat;
if(SIF3&bU3RI)
{
SIF3 = bU3RI; //清除接收完中断
dat = SBUF3;
CH549UART3SendByte(dat);
}
}
#endif
官方库中定义了串口123的中断服务函数。

只要有数据通过串口传入ch549就会立刻触发中断,接受数据。我们可以通过编写中断服务函数来达到我们所需要的目的,此处是将接受到的数据通过串口发送回去,达到数据回环的效果。
USB 转 TTL 模块与串口调试助手的使用方法
USB转TTL模块
套件中所提供的usb转ttl串口模块,他可以让你的计算机也拥有串口模块以此完成与单片机的串口通讯,使用此模块需要安装驱动,驱动为“安装包与所需文件”中的CH341SER.EXE,正常安装即可。

安装完成之后,模块插入电脑即可在设备管理器中的端口处发现模块。

PS:此处需要注意 ch549下载程序时必须断电,因此必须关闭 usb转ttl 串口模块才能打开下载模式.
串口调试助手

第一步:将串口号设置为usb转ttl串口模块的串口号,在我的电脑上为com4。
第二步:将波特率与单片机设置的串口波特率保持一致,可以通过CH549_UART.h中查看设置的波特率。

第三步:打开串口。
实验现象
1.按下单片机的RST键后在接收区看到"helloword"

符合代码

2.在发送区随意发送数据,可以看到接收区也有发送的数据,完成数据回环。
