STM32--微项目13-USART通讯字符串交互并实现点灯控制

一、微项目实现目标:

电脑端发送数据执行,比如:“LED ON”、“LED OFF”,STM32通过获取到数据后,相应对应数据指令,并执行开灯和关灯操作;

二、微项目硬件配置需求:

stm32F103C8T6核心板一块

0.96寸OLED显示,用于显示计数

CH340一块,用于笔记本到串口的传输

LED灯接入都PA1端口

 

 

三、前置知识:

1,文本数据包接受,状态机设定

①当获取到‘@’字符认定为包头,从S=0切到S=1,开始接受数据

②在S=1状态下,当没接受到‘\r’字符,则认定这个数据段的数据,都要接受存放到字符数组中

③在接到‘\r’字符时,则认为实际数据段接受完毕,并且状态切换为S=2;

④在S=2时刻,当收到’\n‘,则认为本轮数据包整体上接受完毕,S=2切换到S=0,为下次进入状态机做准备;

 2,创建发送函数,并且封装为发送字符串数据(当检测到\0时刻,认为本轮数据传输完毕);

3,创建接受函数,并在内部执行状态机

四、代码逻辑分析:

1,配置USART初始化模块

①打开USART1时钟,打开GPIO时钟 

②配置PA9和PA10参数,其中tx配置为复用推挽输出,rx配置为上拉输入模式

③配置USART参数,包括:模式、硬件流控制、传送数据字长、数据位、校验位、停止位

④开启USART中断(准备在中断中进行接受数据包处理,接受数据时刻,触发中断)

⑤配置中断优先级分组

⑥配置NVIC

⑦开启USART
 

2,发送数据模块,并且封装为发送为一个数组。

①主要需要关注的是,发送一个数据位,需要等待发送寄存器为空,才认为数据已经发送;

②封装字符数组发送

3,接受数据包相对就复杂的多,在中断函数中进行配置

①中断函数配置USART1_IRQHandler,中断服务函数的名称一定要与启动文件中的要保持一致;

4,状态机数据流,在中断服务函数中执行
 

5,配置LED模块

①开启GPIOA-PA1的时钟

②配置PA1端口配置,设置为推挽输出端口;

③配置为默认高电平,在硬件配置上,默认低电平点亮LED

6,字符串比较函数,strcmp使用,用于比较接受到的数据;(记得包含cstring的头文件,函数封装在此处)

相等于LED ON,点亮

相等于LED OFF,熄灭

其他,不响应

五、代码示例:

1,配置USART初始化模块

①打开USART1时钟,打开GPIO时钟 

②配置PA9和PA10参数,其中tx配置为复用推挽输出,rx配置为上拉输入模式

③配置USART参数,包括:模式、硬件流控制、传送数据字长、数据位、校验位、停止位

④开启USART中断(准备在中断中进行接受数据包处理,接受数据时刻,触发中断)

⑤配置中断优先级分组

⑥配置NVIC

⑦开启USART

void serial_init(void)
{
	//开启GPIO、USART 时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	//配置GPIO端口,仅使用TX端口,PA9配置为复用推挽输出端口
	 GPIO_InitTypeDef GPIO_InitStruct;
	 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
	 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,& GPIO_InitStruct);
	//开启RX通道,上拉输入
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,& GPIO_InitStruct);
	//配置usart
	USART_InitTypeDef USART_InitStruct;
	USART_InitStruct.USART_BaudRate=9600;
	USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
	USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;//开启RX和TX
	USART_InitStruct.USART_Parity=USART_Parity_No ;
	USART_InitStruct.USART_StopBits=USART_StopBits_1;
	USART_InitStruct.USART_WordLength=USART_WordLength_8b;
	USART_Init( USART1, &USART_InitStruct);
	
	//开启USART中断
	USART_ITConfig( USART1,USART_IT_RXNE, ENABLE);
	//配置NVIC优先级
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	//配置NVIC
	NVIC_InitTypeDef NVIC_InitStruct;
	NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn ;
	NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStruct);
	
	//开启USART
	USART_Cmd(USART1,ENABLE);
	
}

2,发送数据模块,并且封装为发送为一个数组。

①主要需要关注的是,发送一个数据位,需要等待发送寄存器为空,才认为数据已经发送;

②封装字符数组发送

void senddata(uint8_t Byte)
{
	USART_SendData(USART1, Byte);
	while(USART_GetFlagStatus( USART1,USART_FLAG_TXE)==RESET);
}




//发送字符串
void sendstring(char *str)
{
	uint8_t ptr=0;
	while(str[ptr]!='\0')
	{
		senddata(str[ptr++]);
	}
}

3,接受数据包相对就复杂的多,在中断函数中进行配置

①中断函数配置USART1_IRQHandler,中断服务函数的名称一定要与启动文件中的要保持一致;

4,状态机数据流,在中断服务函数中执行

//接受的中断服务函数
void  USART1_IRQHandler(void)
{
	static uint8_t re_state=0;
	static uint8_t pdata=0;
	//静态变量只会初始化一次,与全局变量类似,区别在于静态变量只能在函数内访问
	if(USART_GetITStatus(USART1, USART_IT_RXNE)==SET)
	{
		uint8_t re_data=USART_ReceiveData(USART1);
		//状态执行流
		if(re_state==0 && re_data=='@')
		{
			re_state=1;
			pdata=0;
		}
		else if(re_state==1)
		{
			if(re_data!='\r')
			{
				receive_data[pdata++]=re_data;
			}
			else
			{
				re_state=2;
			}
		}
		else if(re_state==2)
		{
			if(re_data=='\n')
			{
				receive_data[pdata]='\0';
				re_state=0;
				receive_flag=1;
			}	
		}
		
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);
	}
}

5,配置LED模块

①开启GPIOA-PA1的时钟

②配置PA1端口配置,设置为推挽输出端口;

③配置为默认高电平,在硬件配置上,默认低电平点亮LED

④设置函数LED开启和关闭

void ledinit(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	GPIO_InitTypeDef GPIO_InitStruct;
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1 |GPIO_Pin_2 ;
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	GPIO_SetBits(GPIOA,GPIO_Pin_1 |GPIO_Pin_2);
}
void led1_on(void)
{
	GPIO_ResetBits(GPIOA,GPIO_Pin_1);
}

void led1_off(void)
{
	GPIO_SetBits(GPIOA,GPIO_Pin_1);
}

6,字符串比较函数,strcmp使用,用于比较接受到的数据;(记得包含cstring的头文件,函数封装在此处)

相等于LED ON,点亮

相等于LED OFF,熄灭

其他,不响应

在主函数中配置

#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "OLED.H"
#include "SERIAL.H"
#include <cstdio>
#include "key.H"
#include <cstring>
#include "LED.H"


int main()
{
	OLED_Init();
	ledinit();
	OLED_ShowString(1,1,"send_data:");
	serial_init();
//	sendstring("adcd");
	
	

	while(1)
	{
		
		
		if(receive_flag==1)
		{
			OLED_ShowString(2,1,"                ");
			OLED_ShowString(2,1,receive_data);
			
			if(strcmp(receive_data,"LED_ON")==0)
			{
				led1_on();
				sendstring("led1_on ok!");
			}
			if(strcmp(receive_data,"LED_OFF")==0)
			{
				led1_off();
				sendstring("led1_off ok!");
			}
			
			receive_flag=0;
		}
		
	
		
	}
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值