STM32-如何使用串口

一、相关知识储备

1、串行通信与并行同行

  • 串行通信:串行通信就是在数据通信时只使用一根数据线传输数据,将数据一位一位的传输;
  • 并行通信:并行同信就是使用多根数据线传输数据,一次也可以传输多个数据,一般以字或者字节的方式传输;
    区别:数据通信就好像小车在道路上行驶,串行通信就是这条道路上只有一条单车道,同时同向行的车辆只能一个接着一个的过去;而并行通信呢,并行通信就是这条道路上有多条车道,一次可以同时同向行驶多辆小车。

2、同步通信与异步通信

  • 异步通信数据传送按帧传输,一帧数据包含起始位、数据位、校验位和停止位。
  • 同步通信是由1~2个同步字符和多字节数据位组成,同步字符作为起始位以触发同步时钟开始发送或接受数据;多字节数据之间不允许有空隙,每位占用的时间相等;空闲位需发送同步字符。

3、串行通信的机制

  • 单工制式(Simplex)是指双方通信时只能单向传送数据。系统组成以后,发送方和接收方固定。
  • 半双工制式(Half Duplex)是指通信双方都具有发送器和接收器,既可发送也可接收,但不能同时接收和发送,发送时不能接收,接收时不能发送。
  • 全双工制式(Full Duplex)是指通信双方均设有发送器和接收器,并且信道划分为发送信道和接收信道,因此全双工制式可实现双向同时发送和接收数据,发送时能接收,接收时也能发送

4、数据校验

  • 奇偶校验
        奇偶校验在发送数据时,数据位尾随的1的位数为奇偶校验位(1或0),当设置为奇校验时,数据中1的个数与校验位1的个数之和应为奇数;当设置为偶校验时,数据中1的个数与校验位中的1的个数之和应为偶数。
  • 累加和校验
        累加和校验是指发送方将所发送的数据块求和,并将“校验和”附加到数据块末尾。接收方接收数据时也是对数据块求和,将所得结果与发送方的“校验和”进行比较,相符则无差错,否则即出现了差错。
  • 循环冗余码校验
        循环冗余码校验的基本原理是将一个数据块看成一个位数很长的二进制数,然后用一个特定的数去除它,将余数作校验码附在数据块后一起发送。

5、波特率

    波特率是模拟线路信号的速率,也称调制速率,以波形每秒的振荡数来衡量。波其是指数据信号对载波的调制速率,它用单位时间内载波调制状态改变的次数来表示,其单位是波特(Baud)。波特率与比特率的关系是比特率=波特率X单个调制状态对应的二进制位数。在信息传输通道中,携带数据信息的信号单元叫码元,每秒钟通过信道传输的码元数称为码元传输速率,简称波特率。波特率是传输通道频宽的指标。每秒钟通过信道传输的信息量称为位传输速率,简称比特率。比特率表示有效数据的传输速率。

  • 1波特=1位/秒(1bit/s)

6、串行通信的机制

  • 单工通信:单工通信就是指在通信机制建立后,固定接收方与发送方,两者不能够更改,接收方只能够接收,发送方只能够发送;
  • 半双工通信:半双工通信是指在通信机制建立后,接收方与发送方可以互换,但是同一个端口不能够即作为发送方,又作为接收方;
  • 全双工通信:全双工通信是指在通信机制建立后,接收方同时能够作为发送方,同样,发送方也能同时作为接收方;

二、串口(USART)

1、串口介绍

    串口(USART),又称之为通用同步异步收发器(Universal Synchronous/Asynchronous Receiver/Transmitter USART),它提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。 USART利用分数波特率发生器提供宽范围的波特率选择。它支持同步单向通信和半双工单线通信,也支持LIN(局部互连网),智能卡协议和IrDA(红外数据组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。使用多缓冲器配置的DMA方式,可以实现高速数据通信。

2、函数介绍

(1)、USART_InitTypeDefstructure结构体介绍

  • USART_InitTypeDefstructure定义于"stm32f10x_usart.h"文件中,结构体的成员变量如下:
    在这里插入图片描述

  • USART_InitTypeDefstructure成员USART模式对比

  • USART_InitTypeDefstructure成员变量USART_BaudRate的定义
    该成员设置了USART传输的波特率,波特率可以由以下公式计算:
    IntegerDivider =((APBClock)/ (16*(USART_InitStruct->USART_BaudRate)))FractionalDivider = ((IntegerDivider - ((u32)IntegerDivider))*16)+0.5

  • USART_InitTypeDefstructure成员变量USART_WordLenth的定义
    USART_WordLenth定义了在一个帧中数据传输的位数,它有两个值USART_WordLeth_8b(八位数据)与USART_WordLeth_9b(九位数据)。

  • USART_InitTypeDefstructure成员变量USART_StopBits的定义
    USART_StopBits是一个用于设置帧结尾传输的停止位的变量,下表就是对该变量值的详细说明:
    在这里插入图片描述

  • USART_InitTypeDefstructure成员变量USART_Parity的定义
    在这里插入图片描述
    (注意:奇偶校验一旦使能,在发送数据的MSB位插入经计算的奇偶位(字长为9位时的第9位,字长为8位时的第8位)。)

  • USART_InitTypeDefstructure成员变量USART_HardwareFlowControl的定义
    USART_HardwareFlowControl指定了硬件流控制模式使能还是失能。具体模式请看下表:
    在这里插入图片描述

  • USART_InitTypeDefstructure成员变量USART_Mode定义
    USART_Mode设置了串口的使能或者失能发送与接收的模式,下表给出了详细地模式选择:
    在这里插入图片描述

  • USART_InitTypeDefstructure成员变量USART_CLOCK定义
    USART_CLOCK设置了USART时钟是使能还是失能,下面是该变量的选项的详细说明:
    在这里插入图片描述

  • USART_InitTypeDefstructure成员变量USART_CPOL的定义
    USART_CPOL指定了下SLCK引脚上时钟输出的极性。下表是对该变量值的详细说明:
    在这里插入图片描述

  • USART_InitTypeDefstructure成员变量USART_APHA的定义
    USART_CPHA指定了下SLCK引脚上时钟输出的相位,和CPOL位一起配合来产生用户希望的时钟/数据的采样关系。它值详细说明如下图:

在这里插入图片描述

  • USART_InitTypeDefstructure成员变量USART_LastBit的定义
    USART_LastBit来控制是否在同步模式下,在SCLK引脚上输出最后发送的那个数据字(MSB)对应的时钟脉冲。下图给出了参数的可选值与说明:
    在这里插入图片描述

(2)、中断寄存器USART_Init函数

在这里插入图片描述

(3)、中断数据发送USART_SendData函数

在这里插入图片描述

(4)、中断数据接收USART_ReceiveData函数

在这里插入图片描述

(5)、检查指定中断标志位函数USART_GetFlagStatus函数

在这里插入图片描述

2、示例

    利用STM32开发板接收PC端发送的数据,显示在数码管上,并且将接收到数据的累计总个数发送给PC端。

(1)、全局变量

//保存串口1接受到的数据
unsigned char uart1_date[6];
//定义接收到数据的数量
u8 uart1_date_number = 0;
//保存串口1接受到的数据
unsigned char d1,d2,d3;

(2)、主函数

extern unsigned char d1,d2,d3;
 
int main(void)
{ 
	u8 old_number = uart1_date_number;
	time6_init();
	seg_GPIO_Init();
	uart1_init();
	while(1){
		
		segbuff[0] = d1/16;
		segbuff[1] = d1%16;
		segbuff[2] = d2/16;
		segbuff[3] = d2%16;		
		segbuff[4] = d3/16;
		segbuff[5] = d3%16;
		
		//判断是否接收到数据,接收到数据后将数据发送出去
		if(old_number != uart1_date_number){
			sendData(uart1_date_number);
			old_number = uart1_date_number;
		}
		
	}
}

(3)、中断初始化函数

/*
	*	@函数功能:串口1的初始化
	*	@参数 无
	*	@返回值 无
*/
void uart1_init(void)
{
	/* 定义初始化变量 */
	GPIO_InitTypeDef GPIO_InitStructrue;//GPIO初始化
	USART_InitTypeDef USART_InitStructrue;//串口uart1初始化
	NVIC_InitTypeDef NVIC_InitStructrue;//NVIC初始化
	
	/* 开启定时器  */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO,ENABLE);
	
	/*  配置GPIO模式与IO口 用于GPIO初始化  */
	GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_9;//选择GPIO的引脚 UART1输出相关引脚为Pin9
	GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz;//设置GPIO的频率
	GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_AF_PP;//设置GPIO模式为复用推挽输出模式
	GPIO_Init(GPIOA,&GPIO_InitStructrue);
	GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_10;//选择GPIO的引脚 UART1输出相关引脚为Pin9
	GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz;//设置GPIO的频率
	GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_IN_FLOATING;//设置GPIO模式为模拟输入模式
	GPIO_Init(GPIOA,&GPIO_InitStructrue);
	
	/* 串口初始化 */
	USART_InitStructrue.USART_BaudRate = 9600;//设置串口的波特率
	USART_InitStructrue.USART_WordLength = USART_WordLength_8b;//设置数据长度为8位
	USART_InitStructrue.USART_StopBits = USART_StopBits_1;//设置数据有1位的停止位
	USART_InitStructrue.USART_Parity = USART_Parity_No;//串口数据无校验位
	USART_InitStructrue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//将串口设置成失能硬件流
	USART_InitStructrue.USART_Mode = USART_Mode_Tx|USART_Mode_Rx;//开启串口的发送与接收模式
	USART_Init(USART1,&USART_InitStructrue);//初始化USART1
	USART_Cmd(USART1,ENABLE);//使能串口1
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//使能USART1中断
	USART_ClearFlag(USART1,USART_FLAG_TC);//清除USARTx的待处理标志位
	
	/*  设置NVIC的参数  */
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);//设置NVIC的分组
	NVIC_InitStructrue.NVIC_IRQChannel = USART1_IRQn;//指定NVIC通道为USART1通道
	NVIC_InitStructrue.NVIC_IRQChannelPreemptionPriority = 0;//设置中断抢占优先级
	NVIC_InitStructrue.NVIC_IRQChannelSubPriority = 0;//设置中断的响应优先级
	NVIC_InitStructrue.NVIC_IRQChannelCmd = ENABLE;//将中断嵌套设置成使能
	NVIC_Init(&NVIC_InitStructrue);//NVIC初始化	
}

(4)、中断服务函数

/*
	*	@函数功能:串口1的中断服务函数
	*	@参数 无
	*	@返回值 无
*/
void USART1_IRQHandler(void)	
{
	USART_ClearFlag(USART1,USART_FLAG_TC); //清楚中断发送完成的标志位 表示发送数据已经完成
	if(uart1_date_number == 0){
		d1 = USART_ReceiveData(USART1);
	}else if(uart1_date_number == 1){
		d2 = USART_ReceiveData(USART1);
	}else{
		d3 = USART_ReceiveData(USART1);
	}
	uart1_date_number++;
	uart1_date_number = uart1_date_number%3;
}

(5)、数据发送函数

/*
	* 函数功能 发送串口数据
	*参数 u8 data:发送的数据
	*返回值 无
*/
void sendData(u8 data)
{
	USART_SendData(USART1,uart1_date_number);//通过外设USARTx发送单个数据
	//检查发送数据寄存器空标志位是否复位 如果为空表示可以放里面存放数据
	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==Bit_RESET)
		;
}

三、遇到的问题

    在上述代码中需要注意的是:在接收PC端发送过来的数据时最好不要使用数组接收数据。(小编就尝试过,但是会出现发送的数据与数组的数据对应不上的情况)下面附上小编接收数据以及显示数据的方法:

  • 接收数据的方法:
uart1_date[uart1_date_number]=USART_ReceiveData(USART1);//接受串口1的数据
  • 显示数据的方法:

		//尝试1
		segbuff[0] = uart1_date[1];
		segbuff[1] = uart1_date[0];
		segbuff[2] = uart1_date[3];
		segbuff[3] = uart1_date[2];		
		segbuff[4] = uart1_date[5];
		segbuff[5] = uart1_date[4];

		//尝试2
		segbuff[0] = uart1_date[0]/16;
		segbuff[1] = uart1_date[0]%16;
		segbuff[2] = uart1_date[1]/16;
		segbuff[3] = uart1_date[1]%16;	
		segbuff[4] = uart1_date[2]/16;
		segbuff[5] = uart1_date[2]%16;

四、附

  • 在数据发送时,可以不把发送数据的函数放在主函数内,也可以放在串口接受到数据时,这样做,我们就可以不用判断数据是否接收到,每次触发串口中断函数时就可以发送了。
  • 其他相关的函数大家可前往STM32-刷新数码管
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值