1、基本概述
本实验基于stm32c8t6单片机,串口作为基础且重要的外设,具有广泛的应用。本文主要理解串口数据包的发送与接收是如何实现的,重要的是理解程序的实现思路。
2、关键程序
定义好需要用到的变量:
uint8_t rxd_buf[4];//定义数组接收数据包,定长
uint8_t rxd_flag = 0;//接收标志
uint8_t rxd_index = 0;//接收索引
程序理解:
程序放在串口中断函数里面实现。
首先,我们需要定义一个变量用于接收调试串口发过来的数据
u8 recv_dat;
recv_dat =USART_ReceiveData(USART1); USART_ReceiveData()是自带的函数,不需要我们定义,我们使用变量recv_dat接收上位机发送的数据。
2.1接收到数据后,进入switch判断,第一次默认从case 0进入。
2.2如果接收到帧头0xFE,将recv_state置1和索引置0,否则继续等待。
recv_state=1后就进入case 1中,将数据一个一个存入数组rxd_buf[4]中,即rxd_index++。然后我们需要判断是否接收完数据,我这个是接收4个定长数据。
2.3判断接收数据完成后,判断是否接收到帧尾0xFF,接收到帧尾后,将标志位置1,这个标志位是为了方便我们在其它程序里判断执行其它功能。记得将状态清零recv_state =0以接收下一包数据。
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 recv_dat;
static uint8_t recv_state = 0;//默认从索引0开始
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
recv_dat =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
switch(recv_state)
{
case 0:
if(recv_dat == 0XFE)//接收到包头
{
recv_state =1;//切换状态
rxd_index = 0;
}
else
{
recv_state =0;//切换状态
}
break;
case 1:
rxd_buf[rxd_index]=recv_dat;//接收字符
rxd_index++;
if(rxd_index>=4)//判断是否接收数据包完成1
{
recv_state =2;//切换状态
}
break;
case 2:
if(recv_dat == 0XFF)//接收到包尾
{
rxd_flag = 1;//标志位置1
recv_state =0;//并将状态清零,接收下一包数据
}
break;
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断标志位
}
}
完整程序:
usart.c
#include "usart.h"
#include "led.h"
uint8_t txd_buf[4]={1,2,3,4};//数据包
uint8_t rxd_buf[4];//定义数组接收数据包,定长
uint8_t rxd_flag = 0;//接收标志
uint8_t rxd_index = 0;//接收索引
/*******************************************************************************
* 函 数 名 : USART1_Init
* 函数功能 : USART1初始化函数
* 输 入 : bound:波特率
* 输 出 : 无
*******************************************************************************/
void USART1_Init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
/* 配置GPIO的模式和IO口 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;//TX //串口输出PA9
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化串口输入IO */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;//RX //串口输入PA10
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA,&GPIO_InitStructure); /* 初始化GPIO */
//USART1 初始化设置
USART_InitStructure.USART_BaudRate = bound;//波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
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(USART1, &USART_InitStructure); //初始化串口1
USART_Cmd(USART1, ENABLE); //使能串口1
USART_ClearFlag(USART1, USART_FLAG_TC);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启相关中断
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //响应优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、
}
//重定义printf函数
int fputc(int ch,FILE *p) //函数默认的,在使用printf函数时自动调用
{
USART_SendData(USART1,(u8)ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
return ch;
}
//发送字符
void send_byte(uint8_t byte)
{
USART_SendData(USART1,byte);
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);//等待发送完成
}
//发送字符串
void send_string(uint8_t *str)//为什么是指针参数
{
while(*str!='\0') //当字符串不为空时
{
send_byte(*str++);
}
}
//发送一组数据
void send_buf(uint8_t *buf,uint16_t len)
{
uint16_t i;
for(i=0;i<len;i++)
{
send_byte(buf[i]);
}
}
//定义数据包
void send_pack(void)
{
send_byte(0xFE);//包头
send_buf(rxd_buf,4);//数据包
send_byte(0xFF);//包尾
}
/*******************************************************************************
* 函 数 名 : USART1_IRQHandler
* 函数功能 : USART1中断函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 recv_dat;
static uint8_t recv_state = 0;//默认从索引0开始
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断
{
recv_dat =USART_ReceiveData(USART1);//(USART1->DR); //读取接收到的数据
switch(recv_state)
{
case 0:
if(recv_dat == 0XFE)//接收到包头
{
recv_state =1;//切换状态
rxd_index = 0;
}
else
{
recv_state =0;//切换状态
}
break;
case 1:
rxd_buf[rxd_index]=recv_dat;//接收字符
rxd_index++;
if(rxd_index>=4)//判断是否接收数据包完成1
{
recv_state =2;//切换状态
}
break;
case 2:
if(recv_dat == 0XFF)//接收到包尾
{
rxd_flag = 1;//标志位置1
recv_state =0;//并将状态清零,接收下一包数据
}
break;
}
USART_ClearITPendingBit(USART1,USART_IT_RXNE);//清除中断标志位
}
}
usart.h
#ifndef _usart_H
#define _usart_H
#include "system.h"
#include "stdio.h"
extern uint8_t rxd_flag;//接收标志
void USART1_Init(u32 bound);
void send_byte(uint8_t byte);
void send_string(uint8_t *str);
void send_buf(uint8_t *buf,uint16_t len);
void send_pack(void);
#endif
main.c
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "pwm.h"
#include "usart.h"
#include "key.h"
#include "oled.h"
int main()
{
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
USART1_Init(115200);
USART2_Init(115200);
OLED_Init();
KEY_Init();
LED_Init();
send_string("hello stm32");
while(1)
{
if(rxd_flag == 1)
{
rxd_flag = 0;
send_pack();//回显数据包
}
}
}