目录
一. 通信基本概念
1. 根据数据传输方式划分
- 串行通信: 一般是8根数据线以下, 数据一位一位的进行传输.
- 并行通信:一般是指使用8、16、32及64根或更多的数据线进行传输的通讯方式.
2. 根据数据传输方向划分
- 全双工: 同一时刻, 两个设备之间可以同时收发数据.
- 半双工: 两设备之间可以收发数据, 但不能同一时刻.
- 单工: 在任何时刻都只能一个方向通信, 即固定一个设备为发送设备, 另一个固定为接收设备.
3. 根据数据同步方式划分
- 同步通信: 收发设备双方会使用一根信号线表示时钟信号,在时钟信号的驱动下双方进行协调同步数据.
- 异步通信: 不使用时钟信号进行数据同步,它们直接在数据信号中穿插一些同步用的信号位,或者把主体数据进行打包, 以数据帧的格式传输数据.
二. USART流程分析
1. USART协议
- 串口通信协议的数据包内容由: 起始位, 主体数据, 校验位以及停止位组成. 双方需要约定好相同的波特率以及数据包格式, 才能正常通信.
- 波特率: 两个通讯设备之间需要约定好波特率,即每个码元的长度,以便对信号进行解码, 图 串口数据包的基本组成 中用虚线分开的每一格就是代表一个码元。常见的波特率为4800、9600、115200等
- 起始信号和停止信号: 串口通讯的一个数据包从起始信号开始,直到停止信号结束。数据包的起始信号由一个逻辑0的数据位表示, 而数据包的停止信号可由0.5、1(常用)、1.5或2个逻辑1的数据位表示,只要双方约定一致即可。
- 有效数据: 在数据包的起始位之后紧接着的就是要传输的主体数据内容,也称为有效数据,有效数据的长度常被约定为5、6、7或8位长。(一般是8位)
- 数据校验: 分为奇校验和偶校验, 奇校验, 0校验和1校验.奇校验8个数据位加上校验位,其1的数量为奇数.(比如一个8位长的有效数据为:01101001,此时总共有4个“1”, 为达到奇校验效果,校验位为“1”) 后者比较好理解(0校验是不管有效数据中的内容是什么,校验位总为“0”,1校验是校验位总为“1”).
2. USART框图分析
- 从数据发送流程看: 数据从总线进入 ---> 发送数据寄存器(TDR) ---> 发送移位寄存器(移位寄存器不能直接将数据正确发出, 因为他是由发送控制器控制着, 而发送控制器由许多寄存器配置. 以及时钟控制这里也叫波特率)) ---> 最后进入到发送引脚TX(PA9).
3. 寄存器分析
- 控制发送相关寄存器位分析: 从上图发送控制器可以看出, 对其有影响的位有 '发送时钟BRR', 'UE', 'PCE', 'TE', 'RXNE', 'IDLE'等. 具体描述如下图.
- 控制接收相关寄存器位分析: 从上图接收控制器可以看出, 对其有影响的为由: '发送时钟', 'UE', 'PCE', 'RE'等. 具体描述如下图.
- 以上两个公共要用到的寄存器位
三. USART驱动代码
1. 寄存器方式驱动
- 以接受寄存器接受到上位机数据后, 进入中断后将数据发回给上位机.
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_key.h"
#include "delay.h"
#define BAUD 115200
char arr[256] = {0};
uint16_t len = 0;
void USART_Baud(uint32_t baud);
void USART_GPIO_Init_M(void);
void USART_Write_Bit(char *arr, uint16_t len);
void USART_Regiser_Init();
char* USART_Read_Bit();
void NVIC_USART1_Config();
int main()
{
delay_init(72);
USART_GPIO_Init_M();
USART_Regiser_Init();
NVIC_USART1_Config();
while(1)
{
//USART_Read_Bit();
}
}
void USART_GPIO_Init_M(void)
{
GPIO_InitTypeDef GPIO_InitStructe;
GPIO_InitTypeDef GPIO_InitStructe_10;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
GPIO_InitStructe.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructe.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructe.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructe_10.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructe_10.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructe);
GPIO_Init(GPIOA, &GPIO_InitStructe_10);
}
void USART_Regiser_Init()
{
USART1->CR1 |= 1 << 3; //TE: 发送使能
USART1->CR1 |= 1 << 13; //UE: USART使能
USART1->CR1 &= ~(1 << 10); //PCE: 校验位失能
USART1->CR1 &= ~(1 << 12); //M: 字长8个数据位
USART1->CR1 |= 1 << 2; //RE使能
USART1->CR1 |= 1 << 4; //USART中断使能
USART1->CR1 |= 1 << 5; //接受缓冲区中断使能
USART1->CR2 &= ~(0x03 << 12); //STOP: 1个停止位
USART_Baud(BAUD);
}
void USART_Baud(uint32_t baud)
{
float usart_div = 72000000 / 16.0 / baud;
uint16_t div_mantissa = (uint16_t) usart_div;
uint16_t div_fraction = (usart_div - div_mantissa) * 16 + 0.5;
USART1->BRR = (div_mantissa << 4) + div_fraction;
}
void USART_Write_Bit(char *arr, uint16_t len)
{
int i;
USART1->SR;
for(i = 0; i < len; i ++)
{
while((USART1->SR & (1 << 6)) == 0x00); // !!! 等待上一位发送完成需要在前面判断
USART1->DR = arr[i];
//while((USART1->SR & (1 << 7)) == 0x00); // !!! 放后面判断应该是发送寄存器空
}
}
char* USART_Read_Bit()
{
if(((USART1->SR & (1 << 5)) != 0x00))
{
arr[len] = USART1->DR;
len ++;
}
if(((USART1->SR & (1 << 4)) != 0x00))
{
USART1->DR;
USART_Write_Bit(arr, len);
len = 0;
}
return arr;
}
void USART1_IRQHandler()
{
if(((USART1->SR & (1 << 5)) != 0x00))
{
arr[len] = USART1->DR;
len ++;
}
if(((USART1->SR & (1 << 4)) != 0x00))
{
USART1->DR;
USART_Write_Bit(arr, len);
len = 0;
}
}
void NVIC_USART1_Config()
{
NVIC_InitTypeDef NVIC_InitStructe;
//NVIC分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructe.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructe.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructe.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructe.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructe);
}
2. 固件库方式驱动
标签:USART,void,通信,NVIC,详解,InitStructe,GPIO,USART1 From: https://www.cnblogs.com/Deng-S/p/17729041.html