1、通信接口
•通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统
•通信协议:制定通信的规则,通信双方按照协议规则进行数据收发
2、USART
TX(Transmit Exchage):数据发送脚
RX(Receive Exchage):数据接收脚
I2C
SCL(Serial Clock):时钟
SDA(Serial Data):数据
SPI
SCLK(Serial Clock):时钟
MOSI(Master Output Slave Input):主机输出数据引脚
MISO(Master Output Slave Output):主机输入数据引脚
CS(Chip Select):片选,用于指定通信对象
CAN
CAN_H和CAN_L差分数据脚,用两个差分数据脚表示差分数据
USB
DP/D+(Data Positive)和DM/D-(Data Minus)一对差分数据引脚
3、串口通信
1)串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信
2)单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力
4、硬件电路
•简单双向串口通信有两根通信线(发送端TX和接收端RX)
•TX与RX要交叉连接
•当只需单向的数据传输时,可以只接一根通信线
•当电平标准不一致时,需要加电平转换芯片
5、电平标准
•电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:
•
•TTL电平:+3.3V或+5V表示1,0V表示0
•RS232电平:-3~-15V表示1,+3~+15V表示0
•RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)
6、串口参数及时序
•波特率:串口通信的速率
•起始位:标志一个数据帧的开始,固定为低电平
•数据位:数据帧的有效载荷,1为高电平,0为低电平,低位先行
•校验位:用于数据验证,根据数据位计算得来
•停止位:用于数据帧间隔,固定为高电平
举例发送0x0F :0000 1111 低位先行D0-D7:1111 0000
校验位:奇校验 0x0F:D0-TB8/RB8 111100001 0x0E:D0-TB8/RB8 011100000
偶校验同理都以1的数量为基数
7、串口时序
8、波特率
1波特每秒即指每秒传输1个码元符号(通过不同的调制方式,可以在一个码元符号上负载多个bit位信息),1比特每秒是指每秒传输1比特(bit)。因此信息传输速率即比特率在数值上和波特率有这样的关系:
其中I为传信率,S为波特率,N为每个符号承载的信息量,而
以比特为单位。波特率与比特率的关系也可换算成:比特率=波特率*单个调制状态对应的二进制位数。
9、USART简介
•USART(Universal Synchronous/AsynchronousReceiver/Transmitter)通用同步/异步收发器
•USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里
•自带波特率发生器,最高达4.5Mbits/s
•可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)
•可选校验位(无校验/奇校验/偶校验)
•支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN
同步模式增添一个时钟线。硬件流控制:硬件多一根线B就绪置0,未就绪置1A接收到B的反馈信号在B置0时发送数据。
•STM32F103C8T6 USART资源:USART1、 USART2、USART3
10、USART框图
当数据由TDR移动到移位寄存器时会置一个标志位,TXE(TX Empty),发送寄存器空,检查标志位为1时TDR写入下一个数据。向右移位,把数据输出到TX引脚。与串口协议规定低位先行,当新的数据进来,但是移位未完成,将会一直等待。
接收寄存器是从高往低位移动,当移位寄存器接收完成后,整体转移到接收数据寄存器RDF转运过程中也有标志位,RXNE(RX Not Empty)接收数据寄存器为非空,当我们检测到RXNE置为1时,数据读出
流控:一个nRTS(请求发送)输出脚,一个nCTS(清楚发送)输入脚,用于接收外设nRTS的信号。
接收:RTS输出一个能不能接收的反馈信号,接到对方CTS能接收时,RTS就置低电平,请求对方发送,
对方CTS接收后,就可以一直发送数据,当接收处理不过来时,又有新的数据过来,未及时处理,RTS置高电平,对方CTS接收到后,暂停发送,直到接收寄存器处理完成,RTS置低电平,继续传输。
接收同理相反。
USART1挂载在APB2上,所以PCLK2的时钟为72M,其它挂载在APB1,PCLK1时钟,36M.
然后,时钟分频,除一个USARTDIV的分频系数,具有整数部分和小数部分(后四位),分频后/16,得到发射器时钟与接收器时钟,通向控制部分,如果T1为1,发送器使能,发送部分波特率就有效RE为1,接收器使能。
11、USART基本结构
12、数据帧
一般选择9位有校验,8位无校验,刚好为一个字节。
14、起始帧
以波特率的16倍频率采样,一位里采样16次,开始空闲状态一直高电平为采样一直为1,突然采样为0,此处为起始位,然后进行16次采样,无噪声都为0,但实际电路会存在噪声,并且在3、5、7进行一批采样,8、9、10在进行一批采样,采样要求3位中2位为0,如果检测到两个0一个1,状态寄存器置一个NE(Noise Error),噪声标志位,3位中有1个0即前面为噪声所造成,电路忽略前面数据,重新开始捕捉下降沿。后面都会在8、9、10次位置采样。采样位置在最中间
15、数据采样
采样三次和起始位最后相同。如果不全相同会按照2:1的规则来,同时置NE标志位
16、波特率发生器
•发送器和接收器的波特率由波特率寄存器BRR里的DIV确定
•计算公式:波特率 = fPCLK2/1 / (16 * DIV)
17、串口中断接收与发送
1)main
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
uint8_t RxData;
int main(void)
{
OLED_Init();
Serial_Init();
OLED_ShowString(1,1,"RxData:");
//Serial_SendByte(0x41);
// uint8_t MyArray[]={0x42,0x43,0x44,0x45};
// Serial_SendArray(MyArray,4);
//Serial_SendString("HelloWorld!\r\n");
//Serial_SendNumber(12345,5);
//printf("Num=%d\r\n",666);//缺点:重定向到那就只能在那使用
// char String[100];
// sprintf(String,"Num=%d\r\n",666);//格式化的字符串在String里不涉及重定向
// Serial_SendString(String);
//Serial_Printf("Num=%d\r\n",665);
while (1)
{
// Data=Receive();
// OLED_ShowHexNum(1,8,Data,2);//未进中断
if(Serial_GetRxFlag()==1)
{
RxData=Serial_GetRxData();
Serial_SendByte(RxData);
OLED_ShowHexNum(1,8,RxData,2);
}
}
}
2)Serial
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
uint8_t Serial_RxData;
uint8_t Serial_RxFlag;
uint8_t Data;
void Serial_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//输出使用复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//输出使用复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStruture;
USART_InitStruture.USART_BaudRate = 9600;//设置波特率
USART_InitStruture.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//流控
USART_InitStruture.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//选择模式
USART_InitStruture.USART_Parity = USART_Parity_No;//校验位
USART_InitStruture.USART_StopBits = USART_StopBits_1;//停止位
USART_InitStruture.USART_WordLength = USART_WordLength_8b;//字长
USART_Init(USART2,&USART_InitStruture);
/**********开启中断********/
USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruture;
NVIC_InitStruture.NVIC_IRQChannel= USART2_IRQn;
NVIC_InitStruture.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruture.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruture.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStruture);
USART_Cmd(USART2,ENABLE);
}
void Serial_SendByte(uint8_t Byte)
{
USART_SendData(USART2,Byte);
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);//判断发送缓存寄存器,防止数据覆盖
}
void Serial_SendArray(uint8_t *Array,uint16_t Length)
{
uint16_t i;
for(i=0;i<Length;i++)
{
Serial_SendByte(Array[i]);
}
}
void Serial_SendString(char *String)
{
uint8_t i;
for(i = 0;String[i] != '\0';i++)
{
Serial_SendByte(String[i]);
}
}
uint32_t Serial_Pow(uint32_t X,uint32_t Y)
{
uint32_t Result = 1;
while(Y--)
{
Result *= X;
}
return Result;
}
void Serial_SendNumber(uint32_t Number,uint8_t Length)
{
uint8_t i;
for (i=0; i<Length; i++)
{
Serial_SendByte(Number/Serial_Pow(10,Length-i-1)%10+'0');
}
}
/***********************重定向fpuct********************/
/***********************使用printf********************/
int fputc(int ch,FILE *f)
{
Serial_SendByte(ch);
return ch;
}
/************封装Sprintf****************/
void Serial_Printf(char *format,...)
{
char String[100];
va_list arg;//前面类型名,后变量名
va_start(arg,format);//从format位置开始接收参数表,放在arg内
vsprintf(String,format,arg);
va_end(arg);//释放参数表
Serial_SendString(String);
}
uint8_t Receive(void)
{
if(USART_GetFlagStatus(USART2,USART_FLAG_RXNE)==SET)
{
Data=USART_ReceiveData(USART2);
}
return Data;
}
uint8_t Serial_GetRxFlag(void)
{
if(Serial_RxFlag==1)
{
Serial_RxFlag=0;
return 1;
}
return 0;
}
uint8_t Serial_GetRxData(void)
{
return Serial_RxData;
}
void USART2_IRQHandler()
{
if(USART_GetITStatus(USART2,USART_IT_RXNE)==SET)
{
Serial_RxData=USART_ReceiveData(USART2);
Serial_RxFlag = 1 ;
USART_ClearITPendingBit(USART2,USART_IT_RXNE);//手动清楚标志位
}
}