嵌入式开发十八:USART串口通信实验

       上一节我们学习了串口通信的基本理论,串口通信是学习单片机的一个重要的一步,非常重要,这一节我们通过实验来学习串口通信的使用,以及串口的接收中断的使用。

一、发送单个字节uint8_t数据或者字符型数据

实现的功能:

       STM32F4 通过串口和上位机通信,发送单个字节数据(0-255)或者字符给上位机,然后显示在电脑串口助手上。

my_usart.h文件内容

#ifndef  __MY_USART1_H__
#define  __MY_USART1_H__
#include <stdint.h>void My_UsartInit(void);           //串口初始化
void Usart_SendByte(uint8_t date);  //发送一字节函数#endif

my_usart.c文件内容

#include "stm32f4xx.h"
#include "myusart.h"
#include<stdio.h>   //对printf()函数进行重定向引入头文件/******************************第一步:串口时钟使能,GPIO 时钟使能。第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数第三步:GPIO 初始化设置:要设置模式为复用功能第四步:串口初始化:设置波特率,字长,奇偶校验等参数。第五步:使能串口*/void My_UsartInit(void)
{//1.第一步:串口时钟使能,GPIO 时钟使能RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//2.第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//3.第三步:GPIO 初始化设置:要设置模式为复用功能GPIO_InitTypeDef Struct1;Struct1.GPIO_Mode=GPIO_Mode_AF;Struct1.GPIO_Pin=GPIO_Pin_9 |GPIO_Pin_10;Struct1.GPIO_Speed=GPIO_Speed_100MHz;GPIO_Init(GPIOA,&Struct1);//4.第四步:串口初始化:设置波特率,字长,奇偶校验等参数。USART_InitTypeDef Struct2;Struct2.USART_BaudRate=115200;                                        //设置波特率Struct2.USART_WordLength=USART_WordLength_8b;                        //数据位8位Struct2.USART_Parity=USART_Parity_No;                               //无校验位Struct2.USART_StopBits=USART_StopBits_1;                           //1位停止位Struct2.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //不需要硬件流控Struct2.USART_Mode=	USART_Mode_Rx |USART_Mode_Tx;                //设置usart1既可以接收也可以发送USART_Init(USART1,&Struct2);//5.第五步:使能串口USART_Cmd(USART1,ENABLE);}//发送一字节(一个字符)函数
void Usart_SendByte(uint8_t data)
{USART_SendData(USART1,data);       //这是一个库函数,用于将一个字节的数据写入USART的数据寄存器                               while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);    //等待发送完毕}//对printf()函数进行重定向
int fputc(int ch, FILE *f)
{USART_SendData(USART1,ch);                                    //通过串口发送数据,每次发送一个字符while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);    //等待发送完毕return ch;
}

 main.c代码

#include <stdio.h>
#include "myusart.h"int main(void)
{My_UsartInit();printf("发送一个字节:\n");Usart_SendByte('a');printf("\n");Usart_SendByte(97);printf("\n");while(1){}}

关键部分解读:

     发送过程:调用串口发送函数USART_SendData(),但是需要保证在发送下一个字节之前,必须确保当前字节已被成功发送。否则可能会导致新数据写入时覆盖未发送完的数据,造成通信错误。因此,内部使用死循环来控制,调用库函数USART_GetFlagStatus()检查标志位来判断发送的状态!

  • 这个while循环的作用是等待USART的数据寄存器空标志(TXE)被置位。当发送数据寄存器(TDR)中有数据时,TXE标志为RESET。只有当TDR中的数据已被移到移位寄存器中,TXE标志才会被置位。当TXE标志为SET时,表示发送数据寄存器已空,可以发送下一个字节
  • 具体来说,发送数据过程包括:
    1. 将数据写入TDR。
    2. 数据从TDR移到移位寄存器。
    3. 当移位寄存器开始发送数据时,TDR变空,TXE标志被置位。
  • while循环确保在TDR变空之前不会发送新的数据,从而避免数据丢失或覆盖。

 

二、发送一个16位的数据uint16_t

实现的功能:

       STM32F4 通过串口和上位机通信,发送两个字节数据(16位)给上位机,然后显示在电脑串口助手上。我们知道串口通信一次只能发送8位的数据,那么如何实现一次发16位呢?

my_usart.h文件内容

#ifndef  __MY_USART1_H__
#define  __MY_USART1_H__
#include <stdint.h>void My_UsartInit(void);           //串口初始化
void USART_SendHalfWord(uint16_t data);  //发送两个字节函数#endif

my_usart.c

#include "stm32f4xx.h"
#include "myusart.h"
#include <stdio.h>   //对printf()函数进行重定向引入头文件/******************************第一步:串口时钟使能,GPIO 时钟使能。第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数第三步:GPIO 初始化设置:要设置模式为复用功能第四步:串口初始化:设置波特率,字长,奇偶校验等参数。第五步:使能串口*/void My_UsartInit(void)
{//1.第一步:串口时钟使能,GPIO 时钟使能RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//2.第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//3.第三步:GPIO 初始化设置:要设置模式为复用功能GPIO_InitTypeDef Struct1;Struct1.GPIO_Mode=GPIO_Mode_AF;Struct1.GPIO_Pin=GPIO_Pin_9 |GPIO_Pin_10;Struct1.GPIO_Speed=GPIO_Speed_100MHz;GPIO_Init(GPIOA,&Struct1);//4.第四步:串口初始化:设置波特率,字长,奇偶校验等参数。USART_InitTypeDef Struct2;Struct2.USART_BaudRate=115200;                                        //设置波特率Struct2.USART_WordLength=USART_WordLength_8b;                        //数据位8位Struct2.USART_Parity=USART_Parity_No;                               //无校验位Struct2.USART_StopBits=USART_StopBits_1;                           //1位停止位Struct2.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //不需要硬件流控Struct2.USART_Mode=	USART_Mode_Rx |USART_Mode_Tx;                //设置usart1既可以接收也可以发送USART_Init(USART1,&Struct2);//5.第五步:使能串口USART_Cmd(USART1,ENABLE);}//发送两个字节(16位)数据函数
void USART_SendHalfWord(uint16_t data) 
{// 分离高8位和低8位uint8_t tmp_h = data >>0x08;//将date右移8位,取得高8位数据并赋值给tmp_h。右移8位相当于将高8位移到低8位的位置,高8位的原位置被0填充。uint8_t tmp_l = data & 0xFF;//将date和0xff(255,二进制为11111111)高八位为0,进行按位与运算,取得低8位数据并赋值给tmp_l。按位与运算将高8位清零,仅保留低8位。// 发送高8位USART_SendData(USART1, tmp_h);  while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);// 发送低8位USART_SendData(USART1, tmp_l);while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);}//对printf()函数进行重定向
int fputc(int ch, FILE *f)
{USART_SendData(USART1,ch);                                    //通过串口发送数据,每次发送一个字符while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);    //等待发送完毕return ch;
}

main.c

#include <stdio.h>
#include "myusart.h"int main(void)
{My_UsartInit();//发送两个字节的数据USART_SendHalfWord(0xffee);while(1){}}

关键部分解读:

       串行通信接口通常一次只能处理8位数据,那么,我们就可以通过位运算拿到数据的高八位和低八位分别发送,Usart_SendHalfWord函数将16位数据分成两个8位数据(高8位和低8位),然后分别通过Usart_SendByte函数发送出去。这种方式在串行通信中很常见。

使用示例

假设我们有一个要发送的16位数据0x1234

  1. tmp_h = 0x120x1234右移8位得到高8位0x12
  2. tmp_l = 0x340x12340xff按位与得到低8位0x34
  3. 调用Usart_SendByte(pUSARTx, 0x12)发送高8位。
  4. 调用Usart_SendByte(pUSARTx, 0x34)发送低8位。

这确保16位数据能够通过支持8位传输的USART接口完整发送。

三、发送8位的数组(uint8_t)

实现的功能:

       STM32F4 通过串口和上位机通信,发送一个数组(每个元素都是uint8_t类型)或者字符数组给上位机,然后显示在电脑串口助手上。

my_usart.h

#ifndef  __MY_USART1_H__
#define  __MY_USART1_H__
#include <stdint.h>void My_UsartInit(void);           //串口初始化
void Usart_SendByte(uint8_t date);  //发送一字节函数
void USART1_SendArray(uint8_t *array, uint16_t length);//发送一个数组
#endif

my_usart.c

#include "stm32f4xx.h"
#include "myusart.h"
#include<stdio.h>   //对printf()函数进行重定向引入头文件/******************************第一步:串口时钟使能,GPIO 时钟使能。第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数第三步:GPIO 初始化设置:要设置模式为复用功能第四步:串口初始化:设置波特率,字长,奇偶校验等参数。第五步:使能串口*/void My_UsartInit(void)
{//1.第一步:串口时钟使能,GPIO 时钟使能RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//2.第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//3.第三步:GPIO 初始化设置:要设置模式为复用功能GPIO_InitTypeDef Struct1;Struct1.GPIO_Mode=GPIO_Mode_AF;Struct1.GPIO_Pin=GPIO_Pin_9 |GPIO_Pin_10;Struct1.GPIO_Speed=GPIO_Speed_100MHz;GPIO_Init(GPIOA,&Struct1);//4.第四步:串口初始化:设置波特率,字长,奇偶校验等参数。USART_InitTypeDef Struct2;Struct2.USART_BaudRate=115200;                                        //设置波特率Struct2.USART_WordLength=USART_WordLength_8b;                        //数据位8位Struct2.USART_Parity=USART_Parity_No;                               //无校验位Struct2.USART_StopBits=USART_StopBits_1;                           //1位停止位Struct2.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //不需要硬件流控Struct2.USART_Mode=	USART_Mode_Rx |USART_Mode_Tx;                //设置usart1既可以接收也可以发送USART_Init(USART1,&Struct2);//5.第五步:使能串口USART_Cmd(USART1,ENABLE);}//发送一字节函数
void Usart_SendByte(uint8_t data)
{USART_SendData(USART1,data);                                   while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);    //等待发送完毕}//发送一个数组
void USART1_SendArray(uint8_t *array, uint16_t len)
{for (uint16_t i = 0; i < len; i++){Usart_SendByte(array[i]);}
}//对printf()函数进行重定向
int fputc(int ch, FILE *f)
{USART_SendData(USART1,ch);                                    //通过串口发送数据,每次发送一个字符while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);    //等待发送完毕return ch;
}

main.c

#include <stdio.h>
#include "myusart.h"int main(void)
{My_UsartInit();// 要发送的字节数组uint8_t dataArray1[] = {1,2,3,4,5,6,7,8,9,10};int len =sizeof(dataArray1) / sizeof(dataArray1[0]);// 发送一个数组	USART1_SendArray(dataArray1, len);while (1){}}

四、发送字符串数据

实现的功能:

       STM32F4 通过串口和上位机通信,发送字符串给电脑,然后显示在电脑串口助手上。

my_usart.h文件内容

#ifndef  __MY_USART1_H__
#define  __MY_USART1_H__
#include <stdint.h>void My_UsartInit(void);           //串口初始化
void USART1_SendString(char *str);  //发送一个字符串
#endif

my_usart.c文件内容

#include "stm32f4xx.h"
#include "myusart.h"
#include<stdio.h>   //对printf()函数进行重定向引入头文件/******************************第一步:串口时钟使能,GPIO 时钟使能。第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数第三步:GPIO 初始化设置:要设置模式为复用功能第四步:串口初始化:设置波特率,字长,奇偶校验等参数。第五步:使能串口*/void My_UsartInit(void)
{//1.第一步:串口时钟使能,GPIO 时钟使能RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//2.第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//3.第三步:GPIO 初始化设置:要设置模式为复用功能GPIO_InitTypeDef Struct1;Struct1.GPIO_Mode=GPIO_Mode_AF;Struct1.GPIO_Pin=GPIO_Pin_9 |GPIO_Pin_10;Struct1.GPIO_Speed=GPIO_Speed_100MHz;GPIO_Init(GPIOA,&Struct1);//4.第四步:串口初始化:设置波特率,字长,奇偶校验等参数。USART_InitTypeDef Struct2;Struct2.USART_BaudRate=115200;                                        //设置波特率Struct2.USART_WordLength=USART_WordLength_8b;                        //数据位8位Struct2.USART_Parity=USART_Parity_No;                               //无校验位Struct2.USART_StopBits=USART_StopBits_1;                           //1位停止位Struct2.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //不需要硬件流控Struct2.USART_Mode=	USART_Mode_Rx |USART_Mode_Tx;                //设置usart1既可以接收也可以发送USART_Init(USART1,&Struct2);//5.第五步:使能串口USART_Cmd(USART1,ENABLE);}//发送一个字符串
void USART1_SendString(char *str)
{while (*str!='\0'){USART_SendData(USART1,*str);while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);    //等待发送完毕str++;}
}//对printf()函数进行重定向
int fputc(int ch, FILE *f)
{USART_SendData(USART1,ch);                                    //通过串口发送数据,每次发送一个字符while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);    //等待发送完毕return ch;
}

main.c内容:

#include <stdio.h>
#include "myusart.h"int main(void)
{My_UsartInit();// 要发送的字符串char *dataString = "Hello World!";// 发送字符串printf("发送一个字符串:\n");USART1_SendString(dataString);printf("\n");while (1){  }}

五、单片机接收电脑发送的数据显示在串口助手上(接收中断)

       使用串口接收中断可以让CPU在没有数据到达时执行其他任务,而不需要浪费时间轮询接收寄存器。这提高了CPU利用率和系统效率,检查标志位判断是否发生接收中断(USART_IT_RXNE),如果是,读取接收到的数据,然后通过清除接收中断标志以准备接收下一个字节。

实现的功能:

      将接收数据设置为接收中断当上位机发送数据到STM32F407的USART1时,STM32会接收这个数据并通过中断处理函数将数据发送回上位机。上位机的串口助手会显示发送和接收的数据。

my_usart.h

#ifndef  __MY_USART1_H__
#define  __MY_USART1_H__
#include <stdint.h>void USART1_Config(void);        //串口配置
void USART1_SendByte(uint8_t data); //发送一个字节函数
void USART1_IRQHandler(void);      //中断服务函数
#endif

my_usart.c

#include "stm32f4xx.h"
#include "myusart.h"
#include<stdio.h>   //对printf()函数进行重定向引入头文件/******************************第一步:串口时钟使能,GPIO 时钟使能。第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数。第三步:GPIO 初始化设置:要设置模式为复用功能。第四步:串口初始化:设置波特率,字长,奇偶校验等参数。第五步:开启中断并且初始化 NVIC,使能中断(如果需要开启中断才需要这个步骤)。第六步:使能串口。第七步:编写中断处理函数:函数名格式为 USARTxIRQHandler(x 对应串口号)。*/void USART1_Config(void)
{//第一步:串口时钟使能,GPIO 时钟使能RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数。GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);// 第三步:GPIO 初始化设置:要设置模式为复用功能。GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;GPIO_Init(GPIOA, &GPIO_InitStructure);// 第四步:串口初始化:设置波特率,字长,奇偶校验等参数。USART_InitTypeDef   USART_InitStructure;USART_InitStructure.USART_BaudRate = 115200;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_Tx | USART_Mode_Rx;USART_Init(USART1, &USART_InitStructure);// 第五步:开启中断并且初始化 NVIC,使能USART1接收中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// 第六步:使能串口USART_Cmd(USART1, ENABLE);}//发送一字节函数
void USART1_SendByte(uint8_t data)
{USART_SendData(USART1,data);                                   while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);    //等待发送完毕}// 第七步:编写中断处理函数:函数名格式为 USARTxIRQHandler(x 对应串口号)
void USART1_IRQHandler(void)
{if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){// 读取接收到的数据uint8_t receivedData = USART_ReceiveData(USART1);// 将接收到的数据发送回电脑USART1_SendByte(receivedData);// 清除中断标志USART_ClearITPendingBit(USART1, USART_IT_RXNE);}
}//对printf()函数进行重定向
int fputc(int ch, FILE *f)
{USART_SendData(USART1,ch);                                    //通过串口发送数据,每次发送一个字符while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);    //等待发送完毕return ch;
}

main.c

#include "myusart.h"int main(void)
{// 配置USART1USART1_Config();while (1){// 主循环中无需处理接收数据,接收数据在中断中处理}
}

六、向单片机发送指令点亮LED

实现的功能:

    STM32F4 通过串口和上位机通信,发送字符串(指令): open(通过串口助手),然后单片机接收,点亮LED灯;

本实验主要是串口通信的控制功能,演示串口通信可以增强硬件的能力!

my_led..h

#ifndef __MYLED_H
#define __MYLED_Hvoid LED_Init(void);#endif

my_led.c

#include "stm32f4xx.h"                  // Device header
#include "myled.h"/*开时钟  打开外设对应的时钟(查看参考手册,该外设挂在哪个数据总线上),对应GPIO在哪条总线开哪条GPIOF外设 挂在AHB1总线上,所以要打开AHB1的时钟,双击函数,右键->go to definition*/void LED_Init(void)
{//第一步:使能GPIOF的时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能 GPIOF 时钟//第二步:GPIOF9,F10 初始化设置GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//LED0 和 LED1 对应 IO 口GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHzGPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化 GPIO//第三步:设置灯的初始状态GPIO_SetBits(GPIOF,GPIO_Pin_9 | GPIO_Pin_10);//GPIOF9,F10 设置高电平,灯灭
}

my_usart.h

#ifndef  __MY_USART1_H__
#define  __MY_USART1_H__
#include <stdint.h>void USART1_Config(void);        //串口配置
void USART1_IRQHandler(void);  
#endif

my_usart.c

#include "stm32f4xx.h"
#include "myusart.h"
#include "myled.h"
#include "string.h"
#include <stdio.h>   /******************************第一步:串口时钟使能,GPIO 时钟使能。第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数。第三步:GPIO 初始化设置:要设置模式为复用功能。第四步:串口初始化:设置波特率,字长,奇偶校验等参数。第五步:开启中断并且初始化 NVIC,使能中断(如果需要开启中断才需要这个步骤)。第六步:使能串口。第七步:编写中断处理函数:函数名格式为 USARTxIRQHandler(x 对应串口号)。*********************************/void USART1_Config(void)
{//第一步:串口时钟使能,GPIO 时钟使能RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//第二步:设置引脚复用器映射:调用 GPIO_PinAFConfig 函数。GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);// 第三步:GPIO 初始化设置:要设置模式为复用功能。GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;GPIO_Init(GPIOA, &GPIO_InitStructure);// 第四步:串口初始化:设置波特率,字长,奇偶校验等参数。USART_InitTypeDef   USART_InitStructure;USART_InitStructure.USART_BaudRate = 115200;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_Tx | USART_Mode_Rx;USART_Init(USART1, &USART_InitStructure);// 第五步:开启中断并且初始化 NVIC,使能USART1接收中断USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);// 第六步:使能串口USART_Cmd(USART1, ENABLE);}// 第七步:编写中断处理函数:函数名格式为 USARTxIRQHandler(x 对应串口号)
// USART1中断服务程序
void USART1_IRQHandler(void) 
{// 检查USART1是否接收到数据if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {// 读取接收到的字符char received_char = USART_ReceiveData(USART1);// 存储接收到的字符串的缓冲区static char buffer[10];static uint8_t index = 0;if (received_char != '\n' && received_char != '\r')//接收数据的结束标志{// 将字符存储到缓冲区buffer[index] = received_char;index++;} else{//将字符串末尾设置为'\0'buffer[index] = '\0';index = 0;    //置0,为下一次存储做准备// 检查接收到的字符串是否为"open"if (strcmp(buffer, "open") == 0) {// 点亮LED灯GPIO_ResetBits(GPIOF, GPIO_Pin_9| GPIO_Pin_10);    }}}
}//对printf()函数进行重定向
int fputc(int ch, FILE *f)
{USART_SendData(USART1,ch);                                    //通过串口发送数据,每次发送一个字符while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);    //等待发送完毕return ch;
}

      注意:因为我们在程序上面设置了必须输入回车或者换行,串口才认可接收到的数据,所以必须在发送数据后再发送一个回车符, 这里 XCOM 提供的发送方法是通过勾选发送新行实现,如图,只要勾选了这个选项,每次发送数据后,XCOM 都会自动多发一个回车(0X0D+0X0A)。设置好了发送新行,我们再在发送区输入发送的命令:open,然后单击发送,这样灯便会点亮!

 

main.c代码: 

#include <stdio.h>
#include "myusart.h"
#include "myled.h"int main(void)
{LED_Init();USART1_Config();while (1){// 主循环中无需处理接收数据,接收数据在中断中处理}
}

七、主从机通信的两种方式

至此,我们的本次的学习就结束了。通过以上几个实验,相信对串口通信有了深入的理解,这一节我们就讲解到这里,希望能对大家的开发有帮助。 如有兴趣,感谢点赞、关注、收藏,若有不正地方,还请各位大佬多多指教!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/354319.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

XSS跨站脚本攻击

XSS跨站脚本攻击 漏洞原理&#xff1a;接受JS代码&#xff0c;输出JS代码解释执行 网站输出的内容&#xff0c;输入数据能控制。 黑盒XSS手工分析 1、页面中显示的数据找可控的&#xff08;有些隐藏的&#xff09; 2、利用可控地方发送JS代码去看执行加载情况 3、成功执行即…

C#的Switch语句2(case后的值与模式匹配)

文章目录 switch语法结构case具体的值枚举值字符串const关键字 如果没有匹配的值default语句不一定要在最后 模式匹配与C的差异-case穿透&#xff08;Fall-through&#xff09;下一篇文章 switch语法结构 基础的语法结构&#xff0c;在上一篇文章已经写了&#xff0c;具体请看…

斯坦福CS229机器学习中文速查笔记.pdf

斯坦福CS229是一门经典的机器学习课程&#xff0c;算是机器学习领域的明星课&#xff0c;相信不少人在B站上看过这门课的视频。 这门课主要介绍了机器学习和统计模式识别。内容包括&#xff1a;监督学习&#xff08;生成/鉴别学习&#xff0c;参数/非参数学习&#xff0c;神经…

pandas中的loc和iloc

loc和iloc的比较 .loc 和 .iloc 是 pandas 提供的两种不同的索引方法&#xff0c;它们的主要区别在于索引数据的依据&#xff1a; .loc&#xff1a; 基于标签的索引&#xff0c;使用 DataFrame 或 Series 的索引标签&#xff08;即行名和列名&#xff09;来获取数据。可以使用…

2025计算机毕业设计选题题目推荐-毕设题目汇总大全

选题在于精&#xff0c;以下是推荐的容易答辩的选题&#xff1a; SpringBoot Vue选题: 基于SpringBoot Vue家政服务系统 基于SpringBoot Vue非物质文化遗产数字化传承 基于SpringBoot Vue兽医站管理系统 基于SpringBoot Vue毕业设计选题管理系统 基于SpringBoot Vue灾害应急救援…

算法金 | 再见!!!梯度下降(多图)

大侠幸会&#xff0c;在下全网同名「算法金」 0 基础转 AI 上岸&#xff0c;多个算法赛 Top 「日更万日&#xff0c;让更多人享受智能乐趣」 接前天 李沐&#xff1a;用随机梯度下降来优化人生&#xff01; 今天把达叔 6 脉神剑给佩奇了&#xff0c;上 吴恩达&#xff1a;机器…

异构集成封装类型2D、2.1D、2.3D、2.5D和3D封装技术

异构集成封装类型&#xff1a;2D、2.1D、2.3D、2.5D和3D封装详解 简介随着摩尔定律的放缓&#xff0c;半导体行业越来越多地采用芯片设计和异构集成封装来继续推动性能的提高。这种方法是将大型硅芯片分割成多个较小的芯片&#xff0c;分别进行设计、制造和优化&#xff0c;然后…

Java 17的新特性

Java 17引入了多项新特性&#xff0c;以下是一些重要的更新&#xff1a; 增强的伪随机数生成器&#xff08;JEP 356&#xff09; Java 17为伪随机数生成器&#xff08;PRNG&#xff09;提供了新的接口类型和实现&#xff0c;包括可跳转的PRNG和另一类可拆分的PRNG算法&#xf…

【机器学习】 第1章 概述

一、概念 1.机器学习是一种通过先验信息来提升模型能力的方式。 即从数据中产生“模型”( model )的算法&#xff0c;然后对新的数据集进行预测。 2.数据集&#xff08;Dataset&#xff09;&#xff1a;所有数据的集合称为数据集。 训练集&#xff1a;用来训练出一个适合模…

基于GIS、RS、VORS模型、CCDM模型、geodetecto、GWR模型集成的生态系统健康的耦合协调分析

如何集成多源数据&#xff0c;依托ArcGIS Pro和R语言环境&#xff0c;采用“活力-组织力-恢复力-贡献力”&#xff08;VORS&#xff09;模型定量测算生态系统健康指数&#xff08;EHI&#xff09;&#xff1b;如何从经济城镇化&#xff08;GDPD&#xff09;、人口城镇化&#x…

Antd - 上传图片 裁剪图片

目录 本地上传方法【input type"file"】&#xff1a;upload组件【antd】默认接口上传&#xff1a;自定义接口上传&#xff1a;【取消默认上传接口】antd的upload组件beforeUpload还有个比较坑的地方 upload结合裁剪1、antd官方裁剪组件&#xff1a;![在这里插入图片描…

如何通过自己编写Jmeter函数

在Jmeter的函数助手里&#xff0c;有很多内置的函数&#xff0c;比如Random、UUID、time等等。使用这些函数可以快速帮我们生成某些数据&#xff0c;进行一些逻辑处理。用起来非常的方便。 但是在实际接口测试过程中&#xff0c;有很多的需求&#xff0c;Jmeter内置的函数可能…

easyexcel和poi版本冲突报错深入解析v2

easyexcel报错解决 问题 项目由poi改用easyexcel&#xff0c;报错如下&#xff1a; java.lang.NoSuchMethodError: ‘org.apache.poi.ss.usermodel.CellType org.apache.poi.ss.usermodel.Cell.getCellType()’ 原因 easyexcel中的poi和项目原本的poi版本冲突问题。 由于之前做…

移植案例与原理 - HDF驱动框架-驱动配置(2)

1.2.7 节点复制 节点复制可以实现在节点定义时从另一个节点先复制内容&#xff0c;用于定义内容相似的节点。语法如下&#xff0c;表示在定义"node"节点时将另一个节点"source_node"的属性复制过来。 node : source_node示例如下&#xff0c;编译后bar节点…

一文详解扩散模型

文章目录 1、常见的生成模型2、变分推断简介3、文生图的评价指标4、Diffusion Models5、其他技术交流群精选 节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学。 针对算法岗技术趋势、大模型落地…

网络校时服务器:铁路对时有妙招

在信息高速发展的今天&#xff0c;铁路作为国家的经济大动脉&#xff0c;与广大市民生活息息相关&#xff0c;担负着运送大流量乘客、保证交通畅通的重任&#xff0c;为了保证列车的正点运行和乘客的行程&#xff0c;对时间精准度的要求是非常严格的。随着我国铁路的发展速度和…

[AIGC] python遍历以及字符串的切片

以下是一篇关于Python遍历方法和字符串切片的文章&#xff0c;以及一个在LeetCode中的问题进行解释。文章最后会给出解题思路和代码实现。 Python遍历方法与字符串切片入门教程 在Python语言中&#xff0c;我们包含了许多内置的函数和方法令其适合于各种数据处理任务。在这个…

初始化三板斧 - centos7

1、关闭防火墙、关闭SELinux ① 立即关闭防火墙 systemctl stop firewalld ② 设置开机关闭防火墙 systemctl disable firewalld ③ 立即关闭SELinxu setenforce 0 ④ 设置开机关闭SELinux 将SELINUXenforcing 修改替换为 SELINUXdisabled vim /etc/selinux/config se…

java程序监控linux服务器硬件,cpu、mem、disk等

实现 使用Oshi和Hutool工具包1、pom依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.github.oshi</groupId>&l…

【Oracle篇】rman时间点异机恢复:从RAC环境到单机测试环境的转移(第六篇,总共八篇)

&#x1f4ab;《博主介绍》&#xff1a;✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ &#x1f4ab;《擅长领域》&#xff1a;✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux&#xff0c;也在扩展大数据方向的知识面✌️…