一、通信的基本概念
1.1数据的传送方式
数据传送方式可分为串行和并行
串行通讯:数据一位一位地传输,速度慢,但节省数据线成本,可以满足长距离传输数据的要求,抗干扰能力强;
并行通讯:一次能通过8、16、32、64根数据线同时传输多位数据,传输速率快,成本较高,抗干扰能力较弱,一般用于特殊场合,比如芯片内部的总线。
1.2数据的通信方式
单工:只能沿一个方向通信,一方固定发送,另一方固定接收,如广播;
半双工:可沿两个方向通信,但不能同时进行,发送方也能接收,如对讲机;
全双工:可沿两个方向通信,且能同时进行,如手机打电话。
1.3数据的同步方式
根据通讯过程是否使用时钟信号进行同步,可分为:
同步:收发双方在时钟信号的驱动下协调,同步数据。这种方式下传输的数据皆为有效数据,传输效率高;
异步:收发双方时钟不同,而是约定好通信速度,把数据打包成数据块,数据块内不仅包含有效数据,还有对于有效数据的标识,如起始位、校验位、停止位。
1.4数据的通信速率
波特率:每秒传输的码元个数 单位:bps 串口通信中常用
比特率:每秒传输的二进制位数 单位:bit/s
1.5串口电平
串口常用的电平标准:
TTL | 逻辑1 | 2V-5V |
逻辑0 | 0V-0.8V | |
RS232 | 逻辑1 | -3V~-15V |
逻辑0 | 3V~15V |
二、串口通信
根据上面的划分,可知串口通信属于串行、全双工/单工、异步,波特率常设置为9600、115200。
现在的串口通信已经简化到只需要GND、Tx、Rx三根信号线,当只用到GND和另外其中一根时为单工。
三、USART
stm32实现串口通信是通过同步异步收发器USART。但我们通常只使用其中的异步功能,不设置时钟,相当于UART。
一个字符帧的发送需要几部分:起始位+数据帧+可能的奇偶校验位+停止位。
起始位是1个位周期的低电平,位周期就是一位传输占用的时间。
数据帧就是要发送的有效数据,从最低位开始传输。
停止位是n个位周期的高电平(n可设置0.5、1、1.5、2)。可作为串口空闲标志位
波特率在配置寄存器时按如下公式
四、USART库函数配置
4.1相关结构体、函数
(需要同步时才配置)
4.2.配置步骤
1.配置时钟(GPIO、复用、串口)
2.配置GPIO(收- 浮空输入、发 - 复用推挽、50MHz)
3.配置串口(初始化、使能)
4.3如何收发数据
1.发送字符时 要循环等待串口发送标志位空闲,
如:while(USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET);
2.接收字符时进入中断 配置加上NVIC、中断配置
然后写中断函数 查询判断中断状态位 !=RESET ---- 接收
注意!!!串口的中断状态位硬件自动复位 不用手动复位
#include "stm32f10x.h"
#include "usart.h"
#include <stdio.h>
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
void Usart1_Init(void)
{
USART_InitTypeDef usartstructinit;
GPIO_InitTypeDef gpio_structinit;
NVIC_InitTypeDef nvic_structinit;
//配置时钟(GPIO、AFIO、USART1)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//配置GPIO口 TX-A9 RX-A10
gpio_structinit.GPIO_Pin = GPIO_Pin_9;
gpio_structinit.GPIO_Mode = GPIO_Mode_AF_PP;
gpio_structinit.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&gpio_structinit);
gpio_structinit.GPIO_Pin = GPIO_Pin_10;
gpio_structinit.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA,&gpio_structinit);
//配置串口
usartstructinit.USART_BaudRate = 115200; //115200、9600
usartstructinit.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
usartstructinit.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
usartstructinit.USART_Parity = USART_Parity_No;
usartstructinit.USART_StopBits = USART_StopBits_1;
usartstructinit.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1,&usartstructinit);
USART_ITConfig(USART1,USART_IT_RXNE, ENABLE); //串口接收中断使能
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//配置NVIC 配置串口中断
nvic_structinit.NVIC_IRQChannel = USART1_IRQn;
nvic_structinit.NVIC_IRQChannelCmd = ENABLE;
nvic_structinit.NVIC_IRQChannelPreemptionPriority = 1;
nvic_structinit.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&nvic_structinit);
//使能串口
USART_Cmd(USART1,ENABLE);
}
void Send_Byte(char ch)
{
USART_SendData(USART1, ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //空闲后停止位为SET高电平跳出循环
}
void Send_String(char *str)
{
while(*str != '\0')
{
Send_Byte(*str);
str++;
}
Send_Byte('\n');
}
int fputc(int ch,FILE *f)
{
USART_SendData(USART1,(uint8_t)ch);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
uint8_t Serial_GetRxData(void)
{
return Serial_RxData;
}
uint8_t Serial_GetRxFlag(void)
{
if(Serial_RxFlag == 1)
{
Serial_RxFlag = 0;
return 1;
}
return 0;
}
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET)
{
Serial_RxData = USART_ReceiveData(USART1);
Serial_RxFlag = 1;
}
}