基于STM32F407VG开发板USART2串口练习

首先配置USART2串口,配置原理、步骤和USART1类似,具体可见我第一篇笔记中对USART1的配置介绍

void Usart2_Config(u32 brr)
{
	RCC->AHB1ENR |= (1<<0); //打开PA时钟
	RCC->APB1ENR |= (1<<17);//打开usart2的时钟
	
	//初始化PA2复用推挽输出/PA3复用输入
	GPIOA->MODER &= ~(0xf<<4);//清零
	GPIOA->MODER |=  (0xa<<4);//PA9/PA10配置成复用输出模式1010
	GPIOA->OTYPER &= ~(3<<2);//复用推挽输出和输入
	GPIOA->AFR[0] |= (0x77<<8);//复位低位寄存器设置成AF7,映射到usart2
	
	//配置usart2的波特率为115200
	float div;
	u32 div_m,div_f;
	div = (float)42000000/16/brr;//16为过采样倍数
	div_m = (u32)div;//取整数部分
	div_f = (div - div_m)*16+0.5;//取小数部分乘以16后四舍五入
	USART2->BRR = (div_m<<4) | div_f;//配置波特率寄存器,高12位存整数部分,低4位存小数部分
	USART2->CR1 |=  (3<< 2);//接收器和发送器控制使能打开
	USART2->CR1 &= ~(1<<15);//过采样16倍清零
	USART2->CR1 &= ~(1<<12);//字长选择8位
	USART2->CR1 &= ~(1<<10);//禁止奇偶校验
	USART2->CR2 &= ~(3<<12);//选择1位停止位
	USART2->CR1 |=  (1<<13);//usart2使能打开
}
//接收验证
void send_and_rec2(void)
{
	u8 data;
	while(!(USART2->SR & (1<<5)));//上位机写给单片机
	data=USART2->DR;
	while(!(USART2->SR & (1<<7)));//发送到上位机
	USART2->DR=data;
}

1.实现单字符发送数据

void send_a_word(u8 word)
{
	while(!(USART2->SR &(1<<7)));
	USART2->DR = word;
}

2.实现单字符接收数据

u8 receive_a_word(void)
{
	u8 data;
	while(!(USART2->SR &(1<<5)));
	data = USART2->DR;
	return data;
}

3.实现字符串接收数据

void receive_str(u8 *str2)//字符串做形参比做返回值更好操作
{
	while(1)
	{
		*str2=receive_a_word();//需用到单字符接收函数
		if(*str2=='\n')//结束符不唯一 根据应用场景
		{
			break;//循环判断遇到接收换行字符结束循环
		}
		str2++;
	}
	//*str='\0';//'\n'会被'\0'替换掉
	*(str2+1)='\0';//最后一个字符补'\0'
}

4.实现字符串发送到上位机

void send_str(u8 *str1)
{
	while(*str1 != '\0')
	{
		send_a_word(*str1);//需要用到单字符发送函数
		str1++;
	}
}

5.通过A板子的按键KEY1~4控制B开发板的LED1-4的亮灭
main.c文件中:

#include "stm32f4xx.h"
#include "led.h"
#include "key.h"
#include "usart2.h"
	int main()
{
	Usart2_Config(115200);
	led_config();
	key_config();
	u8 data;
	u8 key_value;
	while(1)
	{
		key_value = key_control_another_led();//发送端发出的键值
		send_a_word(key_value);//发出键值
		//led_gets_key_value(key_value);//测试单个板通信
		data = receive_a_word();//接收端接收键值
		led_gets_key_value(data);//接收判断键值
	}
}

USART2.c中写对按键和LED的控制代码

//按键控制另外一个板子的灯.先返回键值
u8 key_control_another_led(void)
{
	static u8 key_flag = 0;
	u8 key_value = 0;
	if((KEY1||!KEY2||!KEY3||!KEY4) && (key_value==0)) 
	{
		delay_ms(200);
		if(KEY1)
		{
			key_flag = 1;
			key_value = 1;
		}
		if(KEY2)
		{
			key_flag = 1;
			key_value = 2;
		}
		if(KEY3)
		{
			key_flag = 1;
			key_value = 3;
		}
		if(KEY4)
		{
			key_flag = 1;
			key_value = 4;
		}
		if(((!KEY1||KEY2||KEY3||KEY4)==1) && (key_flag == 1))
	{
		key_flag = 0;
	}
	}
	return key_value;
}
//接收键值判断灯亮
void led_gets_key_value(u8 key_value)
{
	if(key_value == 1)
		LED1_TURN;
	if(key_value == 2)
		LED2_TURN;
	if(key_value == 3)
		LED3_TURN;
	if(key_value == 4)
		LED4_TURN;

根据原理图配置按键KEY的代码

void key_config(void)
{
	RCC->AHB1ENR |= (1<<0);//打开A端口时钟
	RCC->AHB1ENR |= (1<<4);//打开E端口时钟
	GPIOA->MODER &= ~(3<<0);//GPIOA0配置为输入模式
	GPIOA->PUPDR &= ~(3<<0);//配置无上下拉
	GPIOE->MODER &= ~(0x3F<<4);//GPIOE2/3/4引脚配置为输入模式
	GPIOE->PUPDR &= ~(0x3F<<4);//GPIOE2/3/4引脚配置为无上下拉
}
#define KEY1  (GPIOA->IDR & (1<<0))
#define KEY2 !(GPIOE->IDR & (1<<2))
#define KEY3 !(GPIOE->IDR & (1<<3))
#define KEY4 !(GPIOE->IDR & (1<<4))

根据原理图配置LED灯的代码

void led_config(void)
{
	RCC->AHB1ENR |= (1<<2);//打开C端口时钟源
	GPIOC->MODER &= ~(0XFF<<8);//清零 
	GPIOC->MODER |= (0x55<<8);//配置4-7引脚是通用模式
	GPIOC->OTYPER &= ~(15<<4);//配置4-7引脚是推挽输出
	GPIOC->PUPDR &= ~(0XFF<<8);//配置4-7引脚无上下拉
	GPIOC->ODR |= (15<<4);//每一盏灯都配置灭
}
#define LED1_ON   (GPIOC->ODR &= ~(1<<4))
#define LED1_OFF  (GPIOC->ODR |=  (1<<4))
#define LED1_TURN (GPIOC->ODR ^=  (1<<4))

#define LED2_ON   (GPIOC->ODR &= ~(1<<5))
#define LED2_OFF  (GPIOC->ODR |=  (1<<5))
#define LED2_TURN (GPIOC->ODR ^=  (1<<5))

#define LED3_ON   (GPIOC->ODR &= ~(1<<6))
#define LED3_OFF  (GPIOC->ODR |=  (1<<6))
#define LED3_TURN (GPIOC->ODR ^=  (1<<6))

#define LED4_ON   (GPIOC->ODR &= ~(1<<7))
#define LED4_OFF  (GPIOC->ODR |=  (1<<7))
#define LED4_TURN (GPIOC->ODR ^=  (1<<7))

6.实现A单片机的上位机控制B单片机的LED灯
main.c函数中:

int main()
{
	Usart2_Config(115200);
	led_config();
	key_config();
	u8 ctrl_data[3];
	while(1)
	{
		receive_str(ctrl_data);//A单片机接收字符串
		send_str(ctrl_data);//A单片机传出字符串到另一单片机
		//前面两行烧录到A单片机,下面两行烧录到B单片机
		receive_str(ctrl_data);//烧录到B单片机,B单片机接收字符串
		led_usart(ctrl_data);//B单片机判断字符串
	}
}

USART2.c中代码需加入键值判断LED灯

void led_usart(u8 *arr)
{
	switch(arr[0])
	{
		case '1' :if(arr[1]=='1')LED1_ON;
			else if(arr[1]=='0')LED1_OFF;break;
		case '2' :if(arr[1]=='1')LED2_ON;
			else if(arr[1]=='0')LED2_OFF;break;
		case '3' :if(arr[1]=='1')LED3_ON;
			else if(arr[1]=='0')LED3_OFF;break;
		case '4' :if(arr[1]=='1')LED4_ON;
			else if(arr[1]=='0')LED4_OFF;break;
	}
}

这里需要注意:如果你的电脑上位机输入会自动补’\r\n’换行的话,u8 ctrl_data[]数组要配置至少长度为5,我的电脑上位机输入不会补换行,所以字符串长度3就足够了。

7.开发板1的上位机发送数据给开发板2的上位机
main.c中写入代码即可,但只能实现半双工通信,因为两块板子的USART2接线都已经被占完了

int main()
{
	Usart2_Config(115200);
	u8 data_str[20];
	while(1)
	{
		receive_str(ctrl_data);//A单片机接收字符串
		send_str(ctrl_data);//A单片机传出字符串到另一单片机
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值