stm32串口通信学习分享(一)

        想要分享一下自己学习stm32的过程,这篇分享一下串口通信的相关内容,是自己的一些理解,可能不是很专业全面,请大家谅解。

        主要是用stm32通过串口一发送信息到电脑,在串口调试助手上显示出来,包括发送一个字节,发送两个字节,发送8位数据数组,发送字符串,重定向c库函数printf到串口几个内容来说;

#ifndef    __BSP_USART_H
#define    __BSP_USART_H

#include "stm32f10x.h"
#include <stdio.h>

#define DEBUG_USARTx                                            USART1
#define    DEBUG_USART_CLK                                        RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd                        RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE                            115200

#define DEBUG_USART_GPIO_CLK                            RCC_APB2Periph_GPIOA
#define DEBUG_USART_GPIO_APBxClkCmd                RCC_APB2PeriphClockCmd

#define DEBUG_USART_TX_GPIO_PORT                    GPIOA
#define DEBUG_USART_TX_GPIO_PIN                        GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT                    GPIOA
#define DEBUG_USART_RX_GPIO_PIN                        GPIO_Pin_10

#define DEBUG_USART_IRQ                                        USART1_IRQn
#define DEBUG_USART_IRQHandler                        USART1_IRQHandler

void USART_Config(void);
void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data);
void Usart_SendHalfWord(USART_TypeDef* pUSARTx,uint16_t data);
void Usart_Array(USART_TypeDef* pUSARTx,uint8_t *array,uint8_t num);
void Usart_SendStr(USART_TypeDef* pUSARTx,uint8_t *str);

#endif

        

#include "bsp_usart.h"

static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
    /* 提示 NVIC_PriorityGroupConfig() 在整个工程只需要调用一次来配置优先级分组*/
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}
void USART_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    // 打开串口GPIO的时钟
    DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
    
    // 打开串口外设的时钟
    DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

    // 将USART Tx的GPIO配置为推挽复用模式
    GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
    GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
    
    // 配置串口的工作参数
    // 配置波特率
    USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
    // 配置 针数据字长
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    // 配置停止位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    // 配置校验位
    USART_InitStructure.USART_Parity = USART_Parity_No ;
    // 配置硬件流控制
    USART_InitStructure.USART_HardwareFlowControl = 
    USART_HardwareFlowControl_None;
    // 配置工作模式,收发一起
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    // 完成串口的初始化配置
    USART_Init(DEBUG_USARTx, &USART_InitStructure);
    
    // 串口中断优先级配置
    NVIC_Configuration();
    
    // 使能串口接收中断
    USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);    
    
    // 使能串口
    USART_Cmd(DEBUG_USARTx, ENABLE);        
}

       这里给大家直接展示了项目中变量的宏定义和串口和NVIC的初始化部分,中断在串口通信中的作用是电脑上位机发送信息给单片机时,单片机接收到了就产生中断,并且在中断服务函数里面把电脑发给单片机的内容立马返回去,现在只是stm32通过串口一发送信息到电脑,所以并未用到。

      初始化完成之后就可以编写相应发送字节函数,下面奉上发送一个字节数据函数

void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data)
{
    USART_SendData(pUSARTx, data);
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE)==RESET);
}

       发送一个字节数据函数调用了USART_SendData函数,将串口和通信的数据通过形参传入,用与发送数据,使用USART_GetFlagStatus是获取相应的标志位,其中USART_FLAG_TXE是USART_SR状态寄存器中的位7所控制,通过判断发送数据寄存器是否为空来确定数据是否发送完成,通过此位是0还是1来确定,见下图

      转到程序中,USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE)==RESET说明数据还没有被转移到移位寄存器未发送完成,当为1时表示发送完成跳出循环。

/*发送两个字节数据*/
void Usart_SendHalfWord(USART_TypeDef* pUSARTx,uint16_t data)
{
    uint8_t temp_h,temp_l;
    temp_h = (data&0xff00) >> 8;
    temp_l = data&0xff;
    USART_SendData(pUSARTx, temp_h);
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE)==RESET);
    USART_SendData(pUSARTx, temp_l);
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE)==RESET);
}

        发送两个字节数据函数形参data为16位,可以将其分为高8位和低8位分别发送,通过(data&0xff00) >> 8获取高8位(0xff00转化二进制为1111 1111 0000 0000,data8位数据每位与1相与最终还是data之后再右移,将0000 0000移除,获得temp_h)data&0xff获取低8位(与上述同样原理,但不需要右移),分别发送,最终实发送两个字节数据。

/*发送8位数据数组*/
void Usart_Array(USART_TypeDef* pUSARTx,uint8_t *array,uint8_t num)
{
    uint8_t i;
    for(i = 0;i < num;i++)
    {
        Usart_SendByte(pUSARTx,array[i]);
    }
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC)==RESET);
}

        这个代码是发送8位数组的,感觉这里值得注意的是检测发送是否完成用得是USART_FLAG_TC,其实在这里使用USART_FLAG_TXE经过尝试也是没有问题的,但在发送一字节和两字节数据时使用USART_FLAG_TC会导致数据传输不完整,这个问题未解决。

/*发送字符串*/
void Usart_SendStr(USART_TypeDef* pUSARTx,uint8_t *str)
{
    uint8_t i=0;
    do
    {
        Usart_SendByte(pUSARTx,*(str+i));
        i++;
    }
    while(*(str+i)!='\0');
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC)==RESET);
}

上面是发送字符串的函数,和发送8位数据数组大同小异,不再过多赘述。

        最后再说一下使用printf同样可以将信息发送至串口调试助手,不过需要在串口的.h文件中声明#include  <stdio.h>头文件,同时在串口的.c文件中加入fputc函数重定向c库函数printf到串口

//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch,FILE *f)
{
    /*发送一个字节数据到串口*/
    USART_SendData(DEBUG_USARTx,(uint8_t) ch);
    /*等待发送完毕*/
    while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE)==RESET);
    return (ch);
}

到此,先分享到这里,最后奉上我的main.c和bsp_usart.c和bsp_usart.h文件

main.c文件

#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
int main(void)
{    
    uint8_t a[10]={1,2,3,4,5,6,7,8,9,10};
    //LED_GPIO_Config();     
    USART_Config();
    //Usart_SendByte(DEBUG_USARTx,0X64);
    //Usart_SendHalfWord(DEBUG_USARTx,0xff56);
    //Usart_Array(DEBUG_USARTx,a,10);
    Usart_SendStr(DEBUG_USARTx, "哈哈哈哈 \r\n");
    printf("哈哈哈哈哈 \r\n");
    while (1)
    {
        
    }
}

bsp_usart.c文件

#include "bsp_usart.h"

static void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
  
  /* 嵌套向量中断控制器组选择 */
    /* 提示 NVIC_PriorityGroupConfig() 在整个工程只需要调用一次来配置优先级分组*/
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  
  /* 配置USART为中断源 */
  NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
  /* 抢断优先级*/
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  /* 子优先级 */
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  /* 使能中断 */
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  /* 初始化配置NVIC */
  NVIC_Init(&NVIC_InitStructure);
}

 /**
  * @brief  USART GPIO 配置,工作参数配置
  * @param  无
  * @retval 无
  */
void USART_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    // 打开串口GPIO的时钟
    DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
    
    // 打开串口外设的时钟
    DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

    // 将USART Tx的GPIO配置为推挽复用模式
    GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);

  // 将USART Rx的GPIO配置为浮空输入模式
    GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
    
    // 配置串口的工作参数
    // 配置波特率
    USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
    // 配置 针数据字长
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    // 配置停止位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    // 配置校验位
    USART_InitStructure.USART_Parity = USART_Parity_No ;
    // 配置硬件流控制
    USART_InitStructure.USART_HardwareFlowControl = 
    USART_HardwareFlowControl_None;
    // 配置工作模式,收发一起
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    // 完成串口的初始化配置
    USART_Init(DEBUG_USARTx, &USART_InitStructure);
    
    // 串口中断优先级配置
    NVIC_Configuration();
    
    // 使能串口接收中断
    USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);    
    
    // 使能串口
    USART_Cmd(DEBUG_USARTx, ENABLE);        
}

/*发送一个字节数据*/
void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data)
{
    USART_SendData(pUSARTx, data);
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE)==RESET);
}  

/*发送两个字节数据*/
void Usart_SendHalfWord(USART_TypeDef* pUSARTx,uint16_t data)
{
    uint8_t temp_h,temp_l;
    temp_h = (data&0xff00) >> 8;
    temp_l = data&0xff;
    USART_SendData(pUSARTx, temp_h);
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE)==RESET);
    USART_SendData(pUSARTx, temp_l);
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE)==RESET);
}

/*发送8位数据数组*/
void Usart_Array(USART_TypeDef* pUSARTx,uint8_t *array,uint8_t num)
{
    uint8_t i;
    for(i = 0;i < num;i++)
    {
        Usart_SendByte(pUSARTx,array[i]);
    }
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC)==RESET);
}

/*发送字符串*/
void Usart_SendStr(USART_TypeDef* pUSARTx,uint8_t *str)
{
    uint8_t i=0;
    do
    {
        Usart_SendByte(pUSARTx,*(str+i));
        i++;
    }
    while(*(str+i)!='\0');
    while(USART_GetFlagStatus(pUSARTx, USART_FLAG_TC)==RESET);
}

//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch,FILE *f)
{
    /*发送一个字节数据到串口*/
    USART_SendData(DEBUG_USARTx,(uint8_t) ch);
    /*等待发送完毕*/
    while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE)==RESET);
    return (ch);
}

//重定向c库函数scanf到串口,重定向后可使用scanf,getchar函数
int fgetc(FILE *f)
{
    /*等待串口输入数据*/
    while(USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE)==RESET);
    return (int)USART_ReceiveData(DEBUG_USARTx);
}

bsp_usart.h文件

#ifndef    __BSP_USART_H
#define    __BSP_USART_H

#include "stm32f10x.h"
#include <stdio.h>

#define DEBUG_USARTx                                            USART1
#define    DEBUG_USART_CLK                                        RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd                        RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE                            115200

#define DEBUG_USART_GPIO_CLK                            RCC_APB2Periph_GPIOA
#define DEBUG_USART_GPIO_APBxClkCmd                RCC_APB2PeriphClockCmd

#define DEBUG_USART_TX_GPIO_PORT                    GPIOA
#define DEBUG_USART_TX_GPIO_PIN                        GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT                    GPIOA
#define DEBUG_USART_RX_GPIO_PIN                        GPIO_Pin_10

#define DEBUG_USART_IRQ                                        USART1_IRQn
#define DEBUG_USART_IRQHandler                        USART1_IRQHandler

void USART_Config(void);
void Usart_SendByte(USART_TypeDef* pUSARTx,uint8_t data);
void Usart_SendHalfWord(USART_TypeDef* pUSARTx,uint16_t data);
void Usart_Array(USART_TypeDef* pUSARTx,uint8_t *array,uint8_t num);
void Usart_SendStr(USART_TypeDef* pUSARTx,uint8_t *str);

#endif

谢谢大家观看,学习较浅,有错误之处请大家谅解。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值