基于STM32F401RET6智能锁项目----串口

一、代码例程

二、安装串口驱动

三、(建议安装)串口调试助手

四、验证代码能否实现相应功能

一、代码例程

main.c

#include "stm32f4xx.h"
//#include "led.h"
#include "uart.h"

u8 str[3] = "123";
void Delay(void);
int main()
{
	UART1_Config();//使用相应功能前一定要加Config函数
	while(1)
	{
//		Delay_ms(1000);
//		UART1_Send_Byte('a');
//		UART1_Send_Str((uint8_t *)"Hello\r\n");   //验证串口发送功能时使用这部分代码
//		printf("123456");
	}
	
}

uart.c

#include "uart.h"

//PA9	/USART1_TX	PA9复用推挽输出
//PA10	/USART1_RX	PA10浮空输入

uint8_t U1_R_Buff[100];  //串口1的接收缓冲区
uint8_t U1_R_Length=0;   //串口1已经接收数据的长度
uint8_t U1_R_IDLE=0;     //串口1空闲标志位

void UART1_Config(void)
{
	//1.开GPIOA时钟 
//	void        RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState);  stm32f4xx_rcc.h 976行
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	/*
		GPIO_PinAFConfig函数的作用是配置指定引脚的复用功能。
		在STM32系列的单片机中,每个引脚都有多个功能,可以通过配置引脚的复用功能来选择不同的功能。
		通过GPIO_PinAFConfig函数,可以将指定引脚配置为特定的复用功能,例如串口通信、定时器功能等。
		比如:
		PA9/USART1_TX/TIM1_CH2 42
		PA10/USART1_RX/TIM1_CH3
	*/
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //PA9 复用为 USART1
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);//PA10 复用为 USART1
	

	
	//2.定义结构体   xxx_init准备的
//	void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
	GPIO_InitTypeDef GPIO_InitStruct;
	//3.给结构体赋值  PA9和PA10
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;
	GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
	GPIO_InitStruct.GPIO_Speed=GPIO_Fast_Speed;
	//4.调用xxx_init函数将参数写入到寄存器中 PA9
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
/*	//3.给结构体赋值  PA9	复用推挽输出
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed=GPIO_Fast_Speed;
	//4.调用xxx_init函数将参数写入到寄存器中 PA10
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
*/
	//5.开串口1的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	//6.定义结构体
//void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);	stm32f4xx_usart.h 367行
	USART_InitTypeDef USART_InitStruct;
	//7.给结构体赋值  关于波特率 数据位 校验方式 停止位 要和通信的对方保持一致
	USART_InitStruct.USART_BaudRate = 115200;//波特率  115200 
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控制
	USART_InitStruct.USART_Mode = USART_Mode_Tx|USART_Mode_Rx; //发送使能,接收使能
	USART_InitStruct.USART_Parity =  USART_Parity_No; //无校验
	USART_InitStruct.USART_StopBits = USART_StopBits_1;  //1个停止位
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;  //8个数据位
	//8.调用xxx_init函数将参数写入到寄存器中
	USART_Init(USART1,&USART_InitStruct);
	//9.使能串口功能  xxx_cmd
//	void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);  stm32f4xx_usart.h 371行
	USART_Cmd(USART1,ENABLE);
	//10.根据需求配置是否配置中断
	UART1_NVIC_Config();
	
	
}

void UART1_NVIC_Config(void)
{
	//1.定义结构体
	NVIC_InitTypeDef NVIC_InitStruct={0};

	//11.给结构体赋值
	NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;  //中断通道
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;   //使能对应的中断
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级    void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2; //次级优先级   两个优先级的参数要和分组函数NVIC_PriorityGroupConfig保持一致

	//12.调用XXX_Init函数将参数写入到寄存器中
	NVIC_Init(&NVIC_InitStruct);	
	
	//13.开启对应的中断
//void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);	  stm32f4xx_usart.h 371行
/*	单片机	接收到信息了/信息接收完成了	就会触发中断,执行下面的USART1_IRQHandler函数
	USART_ITConfig	配置中断
	USART1_IRQHandler	中断触发了才会调用该函数
*/
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);  //开启接收中断	
	USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);  //开启空闲中断	
}

//单字节发送 
void UART1_Send_Byte(uint8_t date)
{
//FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);  stm32f4xx_usart.h 390行
//void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);	
	while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);   //参考手册 25.6.1的位6和位7介绍TC和TXE的区别
	/*TXE 为1 表示数据从发送数据寄存器到发送移位寄存器    TC 为1是在前面基础上,发送移位寄存器,将数据发送完成*/
//void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);			 stm32f4xx_usart.h 378行
	USART_SendData(USART1,date);	 //发送数据
	/*TC标志位支持软件清除  参考手册 25.6.1位6 介绍中
	软件清除:先读SR寄存器   USART_GetFlagStatus函数中有读取SR寄存器
					 再写DR寄存器   USART_SendData函数中有写DR寄存器
	*/
}

//发送数组的函数
void UART1_Send_Buff(uint8_t *buf,uint16_t length)
{
	uint16_t i=0;
	for(i=0;i<length;i++)
	{
//		UART1_Send_Byte(*buf++);
		UART1_Send_Byte(buf[i]);
	}
}


//发送字符串的函数
void UART1_Send_Str(uint8_t *str)
{
	while((*str)!='\0')
	{
		UART1_Send_Byte(*str++);
	}
}



/*
printf   fputc  的重写  能够使用printf函数
包含头文件:  #include "stdio.h"
在魔法棒 勾选 Use MicroLIB
仿真:不进mian函数  因为为勾选 Use MicroLIB      LDR     R0, =SystemInit
*/
int fputc(int ch, FILE *f)
{
	UART1_Send_Byte(ch);
	return ch;
}

/*
//查询接收
uint8_t UART1_Rec_Byte(void)
{
	uint8_t Date=0;
//FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);  stm32f4xx_usart.h 390行
//void USART_ClearFlag(USART_TypeDef* USARTx, uint16_t USART_FLAG);		
	while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)!=SET);  //没有收到数据
//uint16_t USART_ReceiveData(USART_TypeDef* USARTx);   stm32f4xx_usart.h 379行
	Date=USART_ReceiveData(USART1);  //参考手册 25.6.1的位5介绍,通过软件序列清除标志位
//	UART1_Send_Byte(Date);
	return Date;
}*/

/*
中断服务函数的编写要求:
1.无参数 无返回值
2.中断服务函数的名字,必须从启动文件startup_stm32f4xx_hd.s中复制
3.中断服务函数中,不要有大量延时操作,及时退出 
4.置标志位 
5.中断服务函数不需要声明
注意:
1.如果仿真,中断服务程序不能放断点,函数名字有错误
2.停止仿真,代码卡在启动文件                B       .位置,没有编写中断服务程序,或者名字有误
*/
/*
接收中断:每接收1个字节,触发1次接收中断
空闲中断:如果检测到总线空闲了(连续10位总线都是高)
对方发过来的数据  0x01  0x02  0x03  0x04
总共触发5次中断:触发4次接收中断,触发1次空闲中断

接收中断中:放断点,会导致后面的数据无法接收
一般在空闲中断中放断点
*/
void USART1_IRQHandler(void)
{
	uint8_t date=0;
//ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);    stm32f4xx_usart.h 392行
//void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);	
	//1.判断中断是否发生
	if(USART_GetITStatus(USART1,USART_IT_RXNE)==SET)
	{ //触发接收中断
		//2.编写中断服务函数执行内容
		date=USART_ReceiveData(USART1);
		USART_SendData(USART1,date);	 //将从串口1接收的信息从串口1发送到电脑,在串口助手中显示
		U1_R_Buff[U1_R_Length++]=date;
		if(U1_R_Length>=100)  //避免数组越界
			U1_R_Length=0;
		//3.清除中断标志位
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);	
	}
	if(USART_GetITStatus(USART1,USART_IT_IDLE)==SET)
	{//触发空闲中断
//uint16_t USART_ReceiveData(USART_TypeDef* USARTx); 		stm32f4xx_usart.h 379行
		date=USART_ReceiveData(USART1);  
		//参考手册 25.6.4的位4的介绍 软件序列清除  先读USART_SR(USART_GetITStatus),然后读USART_DR(USART_ReceiveData)
		U1_R_IDLE=1;	//接收完成标志位置1	
	}
}


uart.h

#ifndef __UART_H__
#define __UART_H__

#include "stm32f4xx.h"
#include "stdio.h"

extern uint8_t U1_R_Buff[100];  //串口1的接收缓冲区
extern uint8_t U1_R_Length;   //串口1已经接收数据的长度
extern uint8_t U1_R_IDLE;     //串口1空闲标志位

void UART1_Config(void);
void UART1_Send_Byte(uint8_t date);
void UART1_Send_Buff(uint8_t *buf,uint16_t length);
void UART1_Send_Str(uint8_t *str);
void UART1_NVIC_Config(void);
uint8_t UART1_Rec_Byte(void);

#endif

二、安装串口驱动

2.1 双击执行串口驱动安装程序,点击下一页

2.2  选择我接受,点击下一页

2.3 安装完成,点击完成

三、(建议安装)串口调试助手

打开电脑自带的 Microsoft Store,搜索串口调试助手,安装它

四、验证代码能否实现相应功能

4.1 验证单字节发送发送、字符串发送、printf改写

main.c部分如下图所示,编译后,将代码下载进单片机

打开之前下载的串口调试助手,按下图进行操作,最终效果如下图

4.2验证串口接收功能

屏蔽掉main.c中发送的这部分代码,可以更好查看接收结果

这行代码负责将从串口1接收的信息从串口1发送到电脑,在串口助手中显示

编译代码,将代码下载进单片机,使用串口助手发送信息,串口助手会收到同样的信息

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值