USART串口发送与接收操作详解

需要用到的USART配置函数

USART_Init();//初始化函数

USART_StructInit();//给结构体赋一个默认初始值

USART_SendData();//发送数据(写DR寄存器)

USART_ReceiveData();//接收数据(读DR寄存器)


配置USART时参考该图流程


【发送数据】

1、完成驱动文件导入操作和编写驱动程序基本代码(参考之前文章)

//将【Serial】驱动文件放在【Hardware】文件夹中

2、在Serial.c中初始化函数
Serial_Init

void Serial_Init(void)

{

//第一步:RCC开启USART和GPIO时钟

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    

//第二步:GPIO初始化,把TX配置成复用输出,RX配置成输入

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA,&GPIO_InitStructure);

    //目前配置:PA9复用推挽输出供USART1的TX使用

    

    

//第三步:配置USART

    USART_InitTypeDef USART_InitSturucture;

    USART_InitSturucture.USART_BaudRate = 9600;//波特率(Init函数内部自动算出波特率对应分配系数)

    USART_InitSturucture.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制

    USART_InitSturucture.USART_Mode = USART_Mode_Tx;//选择发送(接收)模式,若都需要则用‘|’并起来

    USART_InitSturucture.USART_Parity = USART_Parity_No;//校验位

    USART_InitSturucture.USART_StopBits = USART_StopBits_1;//停止位

    USART_InitSturucture.USART_WordLength = USART_WordLength_8b;//字长

    USART_Init(USART1,&USART_InitSturucture);

    //目前配置:9600波特率、8位字长、无校验、1位停止位、无流控、只有发送模式

    

//(只需要发送功能)第四步:开启USART,初始化完成

    USART_Cmd(USART1,ENABLE);

    

//若还需要接收功能,则在开启USART之前完成该步骤    

    

//如果要发送(接收)数据,调用发送(接收)函数即可

//如果要获取发送(接收)状态,调用获取标志位的函数

}

3、在Serial.c中编写发送数据函数
Serial_SendByte

//发送数据函数

//调用这个函数可以从TX引脚发送一个字节数据

void Serial_SendByte(uint8_t Byte)

{    

    //Byte变量写入发送数据寄存器TDR,TDR再传递给发送移位寄存器

    //最后一位一位地把数据移出到TX引脚,完成数据的发送

    USART_SendData(USART1,Byte);

    

    //等待TDR的数据全部转移到移位寄存器

    //数据还在TDR时仍写入数据会产生数据覆盖

    //【USART_FLAG_TXE】发送数据寄存器空标志位

    while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );

    //数据寄存器不空则一直循环,数据寄存器空则跳出循环

}

4、在Serial.h中声明初始化函数
Serial_Init和发送数据函数
Serial_SendByte

void Serial_Init(void);

void Serial_SendByte(uint8_t Byte);

5、在主程序main.c中
#include 
"Serial
.h
"

#include "Serial.h"

6、在主循环之前先初始化Serial

7、在主循环中编写程序主体

int main(void)

{

    

    OLED_Init();

    

    Serial_Init();

    

    Serial_SendByte(0x41);

    //上电后初始化串口,再用串口发送一个0x41

    //调用这个函数之后,TX引脚就会产生一个0x41对应的波形

    while(1)

    {

        

    }

}

实现功能:上电后初始化串口,再用串口发送一个0x41,通过复位键发送数据,可通过电脑端串口软件查看


增加:在Serial.c中封装不同类型数据的发送函数

//发送数据函数

//调用这个函数可以从TX引脚发送一个字节数据

void Serial_SendByte(uint8_t Byte)

{    

    //Byte变量写入发送数据寄存器TDR,TDR再传递给发送移位寄存器

    //最后一位一位地把数据移出到TX引脚,完成数据的发送

    USART_SendData(USART1,Byte);

    

    //等待TDR的数据全部转移到移位寄存器

    //数据还在TDR时仍写入数据会产生数据覆盖

    //【USART_FLAG_TXE】发送数据寄存器空标志位

    while( USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET );

    //数据寄存器不空则一直循环,数据寄存器空则跳出循环

}

//发送数组

/*

第一个参数:数组首地址(数组名)

第二个参数:指定传输多少字节

*/

void Serial_SendArray(uint8_t *Array,uint16_t Length)

{

    uint16_t i;

    for(i = 0; i < Length; i ++)//for循环执行Length次,可以对Array数据进行遍历

    {

        Serial_SendByte(Array[i]);

        //依次取出数组Array的每一项通过SendByte发送

    }

}

//发送字符串

//字符串自带一个结束标志位(数据0),因此不需要传递长度参数

void Serial_SendString(char *String)

{

    uint8_t i;

    for(i = 0; i < String[i] != 0; i ++)//循环条件用结束标志位判断

    {

        Serial_SendByte(String[i]);

        //依次取出字符串String的每一项通过SendByte发送

    }

}

/*

以十进制拆分数据

函数的返回值=X^Y

*/

uint32_t Serial_Pow(uint32_t X,uint32_t Y)

{

    uint32_t Result = 1;

    while( Y — )//循环Y次

    {

        Result *= X;//Result累乘Y次X(X的Y次方)

    }

    return Result;

}

//发送数字(显示十进制字符串形式的数字)

//不同进制的转换参考【OLED.h】

void Serial_SendNumber(uint32_t Number,uint8_t Length)

{

    //把Number的个、十、百位以十进制拆分开

    //转换成字符数字对应的数据并依次发送

    uint8_t i;

    for(i = 0; i < Length ; i ++)//循环Length次

    {

        Serial_SendByte(Number / Serial_Pow(10 , Length – i – 1) % 10 + '0' );

    }

    //i的遍历从0开始,10^0是个位;10^1是十位;10^2是百位,以此类推……

    /*假设Length为2——第一次循环【2-0-1】=1,10^1是十位

                   ——第二次循环【2-1-1】=0,10^0是个位    

    */

    //要以字符的形式显示需要加【偏移】(查ASCII码表)——0x30或'0"

    //参数会以十进制从高位到低位依次发送

}


【基于串口发送】串口发送+接收

  • 查询模式

  • 1、在Serial.c中增加接收部分

    //GPIO口新增使用RX引脚

    //只改变USART选择发送(接收)模式,都需要则用‘|’并起来

    void Serial_Init(void)

    {

    //第一步:RCC开启USART和GPIO时钟

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    //第二步:GPIO初始化,把TX配置成复用输出,RX配置成输入

        GPIO_InitTypeDef GPIO_InitStructure;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOA,&GPIO_InitStructure);

        //目前配置:PA9复用推挽输出供USART1的TX使用

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOA,&GPIO_InitStructure);

        //目前配置:PA10上拉输入供USART1的RX使用

        

        

    //第三步:配置USART

        USART_InitTypeDef USART_InitSturucture;

        USART_InitSturucture.USART_BaudRate = 9600;//波特率(Init函数内部自动算出波特率对应分配系数)

        USART_InitSturucture.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制

        USART_InitSturucture.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//选择发送(接收)模式,都需要用‘|’并起来

        USART_InitSturucture.USART_Parity = USART_Parity_No;//校验位

        USART_InitSturucture.USART_StopBits = USART_StopBits_1;//停止位

        USART_InitSturucture.USART_WordLength = USART_WordLength_8b;//字长

        USART_Init(USART1,&USART_InitSturucture);

        //目前配置:9600波特率、8位字长、无校验、1位停止位、无流控、只有发送模式

        

    //(使用查询模式)第四步:开启USART,初始化完成

        USART_Cmd(USART1,ENABLE);

    }

    2、查询流程:在主函数里不断判断【RXNE】标志位,如果置1说明收到数据,调用【ReceiveData】读取DR寄存器

    3、在主循环中编写程序主体

    uint8_t RxData;

    int main(void)

    {

        OLED_Init();

        

        Serial_Init();

        

        while(1)

        {

            //if成立说明收到数据

            if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET)

            {

            RxData = USART_ReceiveData(USART1);

            //目前接收到的一个字节已经在RxData里了

            OLED_ShowHexNum(1,1,RxData,2);

            }

        }

    }

    实现功能:上电后初始化串口,可通过电脑端串口软件发送指定数据在OLED显示


  • 中断模式

  • 1、在Serial.c中增加中断接收部分

    uint8_t Serial_RxData;

    uint8_t Serial_RxFlag;

    void Serial_Init(void)

    {

    //第一步:RCC开启USART和GPIO时钟

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

        

    //第二步:GPIO初始化,把TX配置成复用输出,RX配置成输入

        GPIO_InitTypeDef GPIO_InitStructure;

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOA,&GPIO_InitStructure);

        //目前配置:PA9复用推挽输出供USART1的TX使用

        

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOA,&GPIO_InitStructure);

        //目前配置:PA10上拉输入供USART1的RX使用

        

    //第三步:配置USART

        USART_InitTypeDef USART_InitSturucture;

        USART_InitSturucture.USART_BaudRate = 9600;//波特率(Init函数内部自动算出波特率对应分配系数)

        USART_InitSturucture.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制

        USART_InitSturucture.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;//选择发送(接收)模式,若都需要则用‘|’并起来

        USART_InitSturucture.USART_Parity = USART_Parity_No;//校验位

        USART_InitSturucture.USART_StopBits = USART_StopBits_1;//停止位

        USART_InitSturucture.USART_WordLength = USART_WordLength_8b;//字长

        USART_Init(USART1,&USART_InitSturucture);

        //目前配置:9600波特率、8位字长、无校验、1位停止位、无流控、只有发送模式

        

        

    //第四步:开启中断

        USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);

        //开启RXNE标志位到NVIC的输出

    //第五步:配置NVIC

    //RXNE标志位一但置1,就会向NVIC申请中断

    //之后可用在中断函数里接收数据

    //中断函数名称查找启动文件【startup_stm32f10x_md.s】

        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组

        NVIC_InitTypeDef NVIC_InitStructure;//初始化NVIC的USART1通道

        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

        NVIC_Init(&NVIC_InitStructure);

        

    //第六步:开启USART,初始化完成

        USART_Cmd(USART1,ENABLE);

    }

    //对Serial_RxData封装Get函数

    uint8_t Serial_GetRxData(void)

    {

        return Serial_RxData;

    }

    //对Serial_RxFlag封装Get函数

    //实现读取后自动清除功能

    uint8_t Serial_GetRxFlag(void)

    {

        if(Serial_RxFlag == 1)

        {

            Serial_RxFlag = 0;

            return 1;

        }

        return 0;

    }

    //中断函数接收数据

    void USART1_IRQHandler(void)

    {

        //判断标志位,如果置1说明收到数据,进入if

        if(USART_GetFlagStatus(USART1,USART_IT_RXNE) == SET)

        {

            Serial_RxData = USART_ReceiveData(USART1);//数据读取到模块的变量里

            Serial_RxFlag = 1;//读取完以后置自己的标志位

            USART_ClearITPendingBit(USART1,USART_IT_RXNE);

        }

    }

    2、中断流程:RXNE标志位一但置1,就会向NVIC申请中断,之后可用在中断函数里接收数据

    3、在主循环中编写程序主体

    uint8_t RxData;

    int main(void)

    {

        OLED_Init();

        

        Serial_Init();

        

        OLED_ShowString(1,1,"RxData:");

        

        while(1)

        {

            //if成立说明收到数据

            if(Serial_GetRxFlag() == 1)

            {

            RxData = Serial_GetRxData();//目前接收到的一个字节已经在RxData里了

            Serial_SendByte(RxData);//数据回传功能

            OLED_ShowHexNum(1,8,RxData,2);

            }

        }

    }

    实现功能:上电后初始化串口,可通过电脑端串口软件发送指定数据在OLED显示


    物联沃分享整理
    物联沃-IOTWORD物联网 » USART串口发送与接收操作详解

    发表评论