串口(UART)的使用

参考:

【STM32学习笔记】(9)——串口通讯(USART)详解_stm32 usart-CSDN博客

stm32学习笔记-9 USART串口_stm32有几个usart_虎慕的博客-CSDN博客

串口概念及分类

简单几句讲明白UART、COM、485、RS232、I2C、SPI区分_com口和485口区别-CSDN博客

串口、COM口、UART口, TTL、RS-232、RS-485区别详解_串口现实形状-CSDN博客

串口的定义,232,485,UART,TTL之间的区别和关系到底是什么_ttl串口通信-CSDN博客

串口、COM口、并口、RS232、USB_串口有哪几种类型-CSDN博客

第001节_辅线1_硬件知识_UART硬件介绍

1. 串口的硬件介绍

UART(Universal Asynchronous Receiver and Transmitter,即通用异步发送接收器(串口)

通过三根线即可,发送、接收、地线(共地)。
Chapter11 lesson1 001.jpg

通过TxD->RxD把ARM开发板要发送的信息发送给PC机。 通过RxD->TxD线把PC机要发送的信息发送给ARM开发板。 最下面的地线统一参考地。

1.2 为什么是通用异步发送接收器?

        在数据中根据所添加的标记信号位的不同方式,分成同步通信和异步通信两种。

        1.“异步通信”是一种很常用的通信方式(效率较低)异步通信在发送字符时,发送端可以在任意时刻开始发送字符,因此必须在每一个字符的开始和结束的地方加上标志,(异步通信是特种兵班)即加上开始位和停止位,以便使接收端能够正确地将每一个字符接收下来。所传送的数据以字节为单位。每个字节前加上一位起始位,每个字节的后面加上停止位。

        特点:字符与字符间的传送是完全异步的,位与位之间的传送基本上是同步的,相邻两字符间的间隔是任意长。简言之,字符间异步,字符内部各位同步。

        好处:异步通信的好处是通信设备简单、便宜,但传输效率较低。

        2.同步通信”的通信双方必须先建立同步,即双方的时钟要调整到同一个频率。收发双方不停地发送和接收连续的同步比特流。一种是使用全网同步,用一个非常精确的主时钟对全网所有结点上的时钟进行同步。一种是使用准同步,各结点的时钟之间允许有微小的误差,然后采用其他措施实现同步传输。同步通信是把所传送的数据以多个字节(100字节以上)为单位,在其前后添加标志(步兵团,必须以班排为一个通讯单位)

        特点:数据块(一组字符)为单位,字符与字符之间、字符内部的位与位之间都同步。

      (SPI IIC为同步通信 ;UART为异步通信)


2. 串口的协议参数

  • 波特率:一般选波特率都会有9600,19200,115200等选项。其实意思就是每秒传输这么多个比特位数(bit),再往本质上说就是 双方约定好每一位所占据的时间
  • 起始位:先发出一个逻辑”0”的信号,表示传输数据的开始。
  • 数据位可以是5~8位逻辑”0”或”1”。如ASCII码(7位),扩展BCD码(8位)。小端传输。
  • 校验位:(原理一句话说清数据位加上这一位后,使得“1”的位数应为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性。以前电子技术没那么稳定,为了保证传输数据的正确性
  • 停止位:它是一个字符数据的结束标志。当传输完这一字节的数据,把电平输出为原来的状态;比如后来又发送一个字符的数据,则下一位又要把电平拉高了,,(双方可以约定,停止位占几个bit的时间)

假如各种位加起来是10位传一个字节,那么115200的波特率就表示,11520字节/s,11kb/s左右。

       Chapter11 lesson1 003.jpg                                                                                                                

以后会经常看到这个符号:115200,8 n 1;8表示8个数据位,n表示 没有校验位,1 表示停止位;

3、串口的广泛应用场景

串口因为结构简单、稳定可靠,广受欢迎。主要的用途有:

  1. 打印调试信息;
  2. 外接各种模块,获取数据:GPS、蓝牙;

大多数ARM芯片都不止一个串口,一般使用串口0来调试,其它串口来外接模块。

ARM芯片上的串口都是TTL电平的,通过板子上或者外接的电平转换芯片(因为开发板上串口使用的是TTL电平,电脑上的USB或者RS232 不是TTL电平),转成RS232接口,连接到电脑的RS232串口上,实现两者的数据传输。

现在的电脑越来越少有RS232串口的接口,而USB是几乎都有的。因此现在把 以前开发板上的USB转RS232芯片 就改成了 USB转串口芯片。   上面的两种方式,对ARM芯片的编程操作都是一样的。  
Chapter11 lesson1 006.jpg        Chapter11 lesson1 005.jpg                                            

4、【串口三大模式之一 轮询模式】通过单片机上一个串口外设实现单片机和串口通信

  • 单片机发送信息到电脑上

 1)结合单片机硬件外设,在CUBEMX IDE下,设置相应引脚为串口TTL模式

2)默认串口协议参数就不修改了,生成代码

cubemx 已经帮助我们初始化了相应引脚,也就是路已经通了

3)现在写业务代码-发送什么

4)烧写代码,连接单片机和电脑

芯片上串口引脚--板上TTL转USB接口--电脑USB接口

+ 串口调试助手

自己做串口调试助手_c++串口通信库比较-CSDN博客一、协议介绍串口调试助手应该都比较熟悉了,主要用于和下位机通信(如单片机),使用的通信协议就是串口通讯协议。首先先介绍下这个协议。 串口通信属于异步的串行通信,有如下几个特点。1 . 物理上的连线至少三根,分别是tx数据发送线,rx数据接收线,GND共用的地线 2. 0与1的约定。RS232电平,约定﹣5V至﹣25V之间的电压信号为1,﹢5V至﹢25V之间的电压信号为0 。TTL电平,约定5V_c++串口通信库比较https://blog.csdn.net/qq_35136212/article/details/78229297?ops_request_misc=&request_id=&biz_id=102&utm_term=%E4%B8%B2%E5%8F%A3%E8%B0%83%E8%AF%95%E5%8A%A9%E6%89%8B%E5%8E%9F%E7%90%86&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-3-78229297.142%5Ev94%5Einsert_down28v1&spm=1018.2226.3001.4187

  • 电脑控制单片机上小灯亮灭

 首先在上面发送数据成功的基础上,做在电脑上发送然后回显回来的小实验

然后,在这个小实验的基础上,解析收到的数据,控制LED小灯

轮询模式缺点

(1)CPU必须一把把数据发送或者接受结束,不能干其他的,程序阻塞住

(2)只能接受固定长度数据


5、串口轮询模式下,发送接受数据控制器功能解析

怎么发送一字节数据,比如‘A‘?

‘A’的ASCII值是0x41,二进制就是01000001,怎样把这8位数据发送给PC机呢?

  1. 双方约定好波特率(每一位占据的时间);
  2. 规定传输协议

Chapter11 lesson1 001.jpg

串口线中的电平变化过程如下(开发板向pc、pc向开发板的原理流程一样):  

   a. 原来是高电平,ARM拉低电平,保持1bit时间;

   b. PC在低电平开始处计时,经过1或者1.5(这块还是不太清楚)个时间单位后,在第一个数据位的中部开始读取数据;再经过1个时间单位,在第二个数据位中部采样数据;,,,,

   c. ARM根据数据依次驱动TxD的电平,同时PC依次读取RxD引脚电平,获得数据;


ARM芯片是如何发送/接收数据?到底是谁来亲历亲为发送的和接受的字符?

        串口轮询模式下,当程序执行到库函数中发送数据的代码时,cpu从内存中把要发送的数据通过串口总线运送到发送缓冲/数据 寄存器,发现不断查询,发现发送移位寄存器空了之后,赶紧接着将数据挪入发送移位寄存器,直到把本次要发送的数据发完或者超时(hal库的recivedata函数底层可能有个循环);最后体现为串口引脚的电平。

        当程序执行到库函数中接受数据的代码时,和上面过程相反。

如图所示串口结构图:

理论上,这块结构应该是所谓 arm处理器的片上(片内)外设,然后从处理器伸出几对输入输出引脚,然后接入电平转换芯片,再从芯片接出几对引脚(接出的这几对引脚有点结成usb串口接口,有的像stm32一样,裸露成引脚)                                                                         
                                                                                                                                                                                                      

注:串口线既然是 串行发送数据,那串口片上外设中一定有一个移位器。

要发送数据时,CPU控制内存要发送的数据通过FIFO传给UART单位,UART里面的移位器,将其内部并行的数据 一位一位 发送出去,在发送完成后产生中断提醒CPU传输完成。

接收数据时,获取接收引脚的电平,逐位放进接收移位器,再放入FIFO,写入内存。在接收完成后接收器或者发送器产生中断(当然也有可能是轮询寄存器)提醒CPU传输完成。

6、串口中断模式下通过pc发送指令点灯

与串口轮询模式最大的区别是:cpu执行hal库 接收或者发送函数的过程中 可以干别的

首先

发送代码稍微改一下;发送过程就可以自动允许中断了

接受代码逻辑上,一样修改下

但是要注意:

接受数据的代码执行可能会被中断,数据没接收完,所以不要急着在面解析数据。这里就要用到中断服务函数。当发现数据接受结束的时候,中断一下,在中断服务函数中分析我们的业务数据。

那么怎样知道数据已经接受结束了呢?我们知道,每次接收移位寄存器把数据放入接收数据寄存器后,就会触发一次 接收数据寄存器非空 中断。

事实上,数据接受完也会触发一次回调中断。这些中断都是同一个串口中断向量。

因此,我们在上面这个函数中书写中断业务代码,即接收到数据后,打开led灯。

测试发现问题及纠正

现象:发送一次电灯指令后,点灯正常;再次发送指令点亮另一个小灯,没点亮。

原因:接收数据代码只等待和执行一次

解决:中断服务函数的末尾再次执行接受数据函数,让他等待着。

7.串口DMA模式以及串口怎么接受不定长数据

目前存在问题1:串口中断模式发送和接受数据的过程中,每次发送数据寄存器数据发送出去或者接受数据寄存器拿到新数据都需要cpu再次搬运变量的下一位数据来发送或者将新数据搬运进变量的下一位。能不能多搞点再搬运,不要这么频繁的麻烦cpu?

解决:在内存变量和发送/接受数据寄存器之间,创建一条通道(DMA),用于数据搬运。

STM32】 DMA原理,步骤超细详解,一文看懂DMA_stm32 dma与cpu同时访问内存_modi000的博客-CSDN博客

在stm32 cubemx中,这是串口的一个功能属性

代码书写时,修改下数据发送和接受的后缀即可。

目前存在的问题2:串口怎么接受不定长数据?

一般串口的轮询/中断模式接受数据时,串口中断控制器会获知要传进来的数据的长度,一旦长度够了,就触发数据接受完成的中断。

解决:使用串口空闲中断

对应 接受 数据函数

开始发送和接受数据时,检测到引脚电平没了会触发结束接受的中断

中断服务函数

8.使用串口蓝牙模块-用蓝牙无线方式控制小灯亮灭

【keysking的STM32教程】第11集 使用蓝牙模块与简易数据包解析_哔哩哔哩_bilibili

第002节_S3C2440_UART编程(标准库-韦东山)

在uart.c这个文件里需要编写这样几个函数:

uart0_init()用于初始化串口
putchar()用于发送一个字符
getchar()用于接收一个字符
puts()用于发送一串字符


在uart0_init()需要做如下几件事:

  • 1. 设置引脚用于串口、端口配置寄存器配置引脚的输入输出:

根据原理图和参考手册设置GPH2,3;引脚用于TxD0, RxD0;并且为了将其保持为高电平,先设置其为上拉;

GPHCON &= ~((3<<4) | (3<<6));//先清空相应位 ;这次不写地址了,开始用宏定义了
GPHCON |=  ((2<<4) | (2<<6));//根据手册设置相应位
GPHUP &= ~((1<<2) | (1<<3));  /* 使能内部上拉 */  //为什么要用这么多 &= 操作,因为不影响其他位

上拉的意思就是设置为高电平;改变一个引脚上电时的一般状态。比如,在设置串口时,我们需要引脚在平时是高电平;这属于数据传输协议的一部分吧。“上拉功能”的原理就是配置相应的寄存器位让上拉电阻和相应的引脚导通,从而输出高电平

  • 2. 设置波特率(先后用到了UCON0、UBRDIVn两个寄存器

将uart设置为PCLK,中断/查询模式:

UCON0 = 0x00000005; /* PCLK,中断/查询模式 */


uart clock=50M,波特率假设是115200,

根据公式UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1     (其中,UART clock(串口波特率发生器时钟)我们默认设置为PCLK,而在前面时钟设置时,我们设置外设时钟是50M,

得到UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1 = 26

UBRDIV0 = 26;

  • 3. 设置数据格式

数据格式设置为常用的8 n1:8个数据位, 无较验位, 1个停止位

ULCON0 = 0x00000003; /* 8n1: 8个数据位, 无较验位, 1个停止位 */

注:我们写这是最简单的串口程序了。还有很多具有强大功能的串口寄存器还没有配置,比如FIFO寄存器

  • 4.寄存器配置完该写功能函数使用寄存器了

//字符发送函数原理:循环查看发送/接受状态寄存器的第2位,示意发送器是否为空;如果为空,就可以给发送器中的发送缓冲寄存器装入数据了
int putchar(int c)
{
/* UTRSTAT0 */ //uart 发送 接受 状态 寄存器
/* UTXH0 */       //串口 发送 缓冲 寄存器

 while (!(UTRSTAT0 & (1<<2)));//读取UTRSTAT0寄存器,查询其第2位判断发送buff是否为空,即上一次发送是否完成,如果完成即向UTXH0写入要发送的新数据;查询其第0位判断接收buff是否为空,即本次接收是否完成,如果接收完成,读取URXH0的值。
UTXH0 = (unsigned char)c;

}


//字符接受原理:循环查看  发送/接受状态寄存器的第 0位,是否接受缓冲寄存器为空;为空就可以继续接受了
int getchar(void)//接受单字符函数
{
while (!(UTRSTAT0 & (1<<0)));//第 0 位是否为空
return URXH0;//将 串口接受缓冲器中的值返回到主函数
}

int puts(const char *s)//发送字符串函数
{
while (*s)      // 这因该是利用了字符串结尾是个空字符                                                                                                                                               
{
  putchar(*s);
  s++;
}
}

在主函数里,先调用初始化函数,然后循环获取用于输入的数据,然后回显出来。(这么一来,四个函数就都用到了)。并且在收到`\r`回车时,输出`\n`换行,有些时候`\n`是回车,那输出`\r`换行。

 
 
#include "s3c2440_soc.h"
#include "uart.h"

int main(void)
{
	unsigned char c;
	
	uart0_init();
	puts("Hello, world!\n\r");
	
	while(1)
	{
		c = getchar();//开机后,屏幕上直接打印出hello world!,然后其他什么也没有;此时你在pc端通过串口界面发送一个字符,单单一个接受字符函数无法验证功能;后面再写一个发送字符函数,作为单片机向pc的回显。pc接收到发回来的串口信息后,就调用它里面的接受函数和显示函数,显示在pc屏幕上
		if (c == '\r')  //写中间这两个if的目的是:当你输入一些字符时,pc正常显示出一些字符;当你回车想换行输入时,“回车”也是一个pc发送的字符,单片机上的c就被赋值为 \r或者 \n。这俩字符的功能都是回到行首。

		{
			putchar('\n');
		}

		if (c == '\n')
		{
			putchar('\r');
		}

		putchar(c);//回显
	}
	return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值