首先配置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单片机传出字符串到另一单片机
}
}