6.USART串口协议

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);//手动清楚标志位
    }        
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值