hc05蓝牙模块

开始

复制代码
	模块上电未连接时快闪,此时为AT模式,可以进行相关设置,配对连接后慢闪进入透传模式,可以发送HEX格式数据和文本格式数据  文本格式数据需要发送方和接收方设置相同的编码格式(GBK /UTF-8)。
	有时不能进人AT模式,则需要按下模块上的按键再通电,如果发送AT指令还是没响应再修改一下波特率为38400试试。

蓝牙串口小程序的使用

复制代码
	使用USB_ttl模块连接蓝牙模块到电脑,TXRX需要交叉连接供电5V。
发送界面
复制代码
	发送区界面选择编辑可以增减按键,滑杆,摇杆的数量。点击单个控件可以设置控件的发送内容,修改控件名称。按键可以选择是否自锁(类似于自锁开关,按下是锁定在按下状态,想要松开需要再次按下按键),选择数据格式:(HEX,文本)。摇杆可以设置名称,最大值最小值,步距。

	数据包格式发送时接收方需要设置为文本格式。

按键数据包格式[key,按键名称,按键状态] 例如:[key,1,down]
滑杆数据包格式[slider,滑杆名称,滑杆位置] 例如:[slider,1,45]
摇杆数据包格式[joystick,左摇杆横向值,左摇杆纵向值,,右摇杆横向值,右摇杆纵向值] 例如:[joystick,83,30,0,0]

接收界面

显示屏

发送方发送文本数据包格式:[display,x坐标,y坐标,字符串,字号大小]

字号可以省略,默认为18

示例:[display,0,0,helloworld,18]

清空指令:[display-clear]

使用单片机发送字符串打印数字时需要指定数字的显示长度。

特殊情况:[display,0,0,hello,66,18] 66是需要显示的内容时末尾的字号不能省略不然会被解析为字号。

可以参看接收区的内容来调试显示屏。
绘图

绘图数据包格式:[plot,数据1,数据2,数据三...]

清空绘图区域:[plot-clear]

蓝牙模块与单片机通信

回顾一下串口收发文本数据的代码

PA9复用推完,PA10上拉输入(串口空闲高电平)。

接收状态机:

数据包以@符号开始,结束为 :\r\n

接收完一包数据后置标志位,主循环检测标志位执行相应动作。

c 复制代码
void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		uint8_t RxData = USART_ReceiveData(USART1);
		
		if (RxState == 0)
		{
			if (RxData == '@' && Serial_RxFlag == 0)
			{
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1)
		{
			if (RxData == '\r')
			{
				RxState = 2;
			}
			else
			{
				Serial_RxPacket[pRxPacket] = RxData;
				pRxPacket ++;
			}
		}
		else if (RxState == 2)
		{
			if (RxData == '\n')
			{
				RxState = 0;
				Serial_RxPacket[pRxPacket] = '\0';
				Serial_RxFlag = 1;
			}
		}
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

按键实现开关灯

发送:@LED_ON 开灯 @LED_OFF 关灯

只需要设置按键按下发送文本:"@OLED_ON"末尾有换行 松开发送"@LED_OFF"
串口输出到显示屏

c 复制代码
	uint8_t a=66;
	printf("[display,0,0,helloworld,22]");
	printf("[display,0,20,a:%03d]",a);

串口绘图

绘制正弦曲线

c 复制代码
		float x,y1,y2;
		x+=0.1;
		y1=sin(x);
		y2=cos(x);
		printf("[plot,%f,%f]",y1,y2);

解析数据包

需要修改接收状态机代码,因为数据包格式是"[ str1,str2,str3...]"

c 复制代码
void USART1_IRQHandler(void)
{
	static uint8_t RxState = 0;
	static uint8_t pRxPacket = 0;
	if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
	{
		uint8_t RxData = USART_ReceiveData(USART1);
		
		if (RxState == 0)
		{
			if (RxData == '[' && Serial_RxFlag == 0)
			{
				RxState = 1;
				pRxPacket = 0;
			}
		}
		else if (RxState == 1)
		{
			if (RxData == ']')
			{
				RxState = 0;
				Serial_RxPacket[pRxPacket] = '\0';
				Serial_RxFlag = 1;
			}
			
			else
			{
				Serial_RxPacket[pRxPacket] = RxData;
				pRxPacket ++;
			}
		}

		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

测试一下:手机发送区写入[hello,world,ok],接收区应该是分割后的字符串

c 复制代码
	while (1)
	{

		if (Serial_RxFlag == 1)
		{
			OLED_ShowString(4,1,"             ");
			OLED_ShowString(4,1,Serial_RxPacket);
			
			char * substr1=strtok(Serial_RxPacket,",");
			char * substr2=strtok(NULL,",");
			char * substr3=strtok(NULL,",");
				
			printf("%s,%s,%s\r\n",substr1,substr2,substr3);
			Serial_RxFlag = 0;
		}
	}

测试按键,这里需要在手机软件上设置key1,key2的名称以及发送的时机,发送数据包内容太为[key,1,up],[key,2,down]

c 复制代码
char * tag=strtok(Serial_RxPacket,",");
			if(strcmp(tag,"key")==0){
				char * num=strtok(NULL,",");
				char * action=strtok(NULL,",");
				if(strcmp(num,"1")==0 && strcmp(action,"up")==0){
					printf("key,1,up\r\n");
					LED1_ON();
				}else if(strcmp(num,"2")==0 && strcmp(action,"down")==0){
					printf("key,2,down\r\n");
					LED1_OFF();
				}

同理滑杆数据包的解析的代码很类似,这样调节PID就很方便了

c 复制代码
else if(strcmp(tag,"slider")==0){
				char * name=strtok(NULL,",");
				char * value=strtok(NULL,",");
				
				if(strcmp(name,"1")==0 ){
					printf("slider,1,value:%d\r\n",atoi(value));

				}else if(strcmp(name,"2")==0 ){
					printf("slider,2,value:%0.2f\r\n",atof(value));
;
				}
			}

解析摇杆数据包

c 复制代码
else if(strcmp(tag,"joystick")==0){
				int8_t LH=atoi(strtok(NULL,","));
				int8_t LV=atoi(strtok(NULL,","));
				int8_t RH=atoi(strtok(NULL,","));
				int8_t RV=atoi(strtok(NULL,","));
				
				printf("joystick:%d,%d,%d,%d\r\n",LH,LV,RH,RV);
				
			}

库函数的使用:
strcmp:

c 复制代码
/*
返回值:
	0:字符串相等
	<0:s1<s2
	>0:s1>s2
比较是按字典顺序进行的,比如stra<strb
*/
int strcmp(const char *s1, const char *s2);

strtok:

c 复制代码
/*
按分隔符delim分割字符串str
首次调用传入待分割的字符串,后续调用传入NULL
返回下一个标记,无标记返回NULL。
*/
char *strtok(char *str, const char *delim);


不能使用字面值常量

atoi:

c 复制代码
int atoi(const char *nptr);

将字符串转换为整数,跳过前导空白字符,遇到非数字字符停止转换,返回转换后的整数值
atof:

c 复制代码
double atof(const char *nptr);

将字符串转换为双精度浮点数,跳过前导空白字符,支持科学计数法(如"3.14e-2"),返回转换后的浮点数值

总结

复制代码
蓝牙模块的使用其实就是串口通信,在AT模式下设置好波特率后就可以进行信息传输,APP端需要了解按键,滑杆,摇杆,以及绘图数据包的格式  。单片机中需要使用库函数对数据包内容进行解析。
@江协科技
相关推荐
逐步前行6 小时前
STM32_TIM_寄存器操作
stm32·单片机·嵌入式硬件
0南城逆流06 小时前
【STM32】知识点介绍七:PWM功能
stm32·单片机·嵌入式硬件
智者知已应修善业7 小时前
【51单片机独立按键控制数码管移动反向,2片74CH573/74CH273段和位,按键按下保持原状态】2023-3-25
经验分享·笔记·单片机·嵌入式硬件·算法·51单片机
dashizhi20157 小时前
服务器共享禁止保存到本地磁盘、共享文件禁止另存为本地磁盘、移动硬盘等
运维·网络·stm32·安全·电脑
我是一棵无人问荆的小草7 小时前
单片机通电后延迟启动策略
单片机·嵌入式硬件
日更嵌入式的打工仔8 小时前
UART RX为什么要上拉
单片机
华奥系科技9 小时前
智慧经济新格局:解码社区、园区与城市一体化建设逻辑
大数据·人工智能·科技·物联网·安全
TDengine (老段)10 小时前
TDengine IDMP 组态面板 —— 画布
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
三佛科技-1873661339711 小时前
FT32F030F6AP7高性能32位RISC内核MCU解析(兼容STM32F030K6TP7)
stm32·单片机·嵌入式硬件
LCMICRO-1331084774611 小时前
长芯微LDC90810完全P2P替代ADC128D818,是一款八通道系统监控器,专为监控复杂系统状态而设计。
stm32·单片机·嵌入式硬件·fpga开发·硬件工程·模数转换芯片adc