云计算百科
云计算领域专业知识百科平台

HC-05蓝牙与STM32进行APP通信实战教程---第三期stm32利用cubemx生成代码----STM32部分完结篇

功能简介:

OLED菜单 按键控制 继电器控制 风扇挡位控制 串口收发控制 HC-05蓝牙模块和SU-03T语言模块

功能实现:

智能降温水杯演示视频

资源分享:

通过网盘分享的文件:STM32代码 链接: https://pan.baidu.com/s/1nnrzI7XCiDqsLK5JA550oQ?pwd=6666 提取码: 6666  –来自百度网盘超级会员v1的分享

我这边直接给出源码,由于配置地方较多,可能会存在配置出错

我这边还是会将重点的cubemx的配置着重说明 代码部分挑重点了

cubemx配置

HC-05的使用参考这篇博客 HC-05蓝牙模块与手机APP通信(HC-05 AT指令配置)-CSDN博客

串口1配置——-接蓝牙HC-05模块

串口1的DMA配置 

使能USART1中断

串口2配置—–接SU-03T语音模块

注意:波特率是SU-03T语音模块的波特率来定的

SU-03T语音模块使用参考这篇博客

SU-03T语言模块实现串口收发功能-CSDN博客

串口2的DMA配置 

使用USART2中断

TIM4 PB8风扇PWM配置

其他GPIO口配置

GPIO引脚配置就按照下图的来就行 包含按键和继电器的

配置所有引脚图

代码部分

串口1和串口2 DMA空闲中断部分

点击usart.c文件

变量定义

uint8_t RxBuffer[RxBufferSize]={0};
uint16_t RxNum=0;
uint8_t flag_idie=0;

uint8_t RxBuffer2[RxBufferSize]={0};
uint16_t RxNum2=0;
uint8_t flag_idie2=0;

//使能串口1空闲中断
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
//使能串口1DMA接受
HAL_UART_Receive_DMA(&huart1,RxBuffer,RxBufferSize);

//使能串口2空闲中断
__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);
//使能串口2DMA接受
HAL_UART_Receive_DMA(&huart2,RxBuffer2,1024);

usart.h头文件声明

#define RxBufferSize 1024
extern uint8_t RxBuffer[];
extern uint16_t RxNum;
extern uint8_t flag_idie;
extern uint8_t RxBuffer2[];
extern uint16_t RxNum2;
extern uint8_t flag_idie2;

stm32f1xx_it.c文件下

/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE)==SET)//空闲中断IDLE标志位 发生置位
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除空闲中断标志位
//int temp;
//temp = huart1.Instance->SR; //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
//temp = huart1.Instance->DR; //读取数据寄存器中的数据
HAL_UART_DMAStop(&huart1);// 停止DMA传输
RxNum=RxBufferSize-__HAL_DMA_GET_COUNTER(&hdma_usart1_rx);//总计数减去未传输的数据个数,得到已经接收的数据个数 __HAL_DMA_GET_COUNTER(&hdma_usart1_rx)获取DMA中未传输的数据个数
flag_idie=1;// 接受完成标志位置1
}
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */

/* USER CODE END USART1_IRQn 1 */
}

/**
* @brief This function handles USART2 global interrupt.
*/
void USART2_IRQHandler(void)
{
/* USER CODE BEGIN USART2_IRQn 0 */
if(__HAL_UART_GET_FLAG(&huart2,UART_FLAG_IDLE)==SET)//空闲中断IDLE标志位 发生置位
{
__HAL_UART_CLEAR_IDLEFLAG(&huart2);//清除空闲中断标志位
//int temp;
//temp = huart2.Instance->SR; //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
//temp = huart2.Instance->DR; //读取数据寄存器中的数据
HAL_UART_DMAStop(&huart2);// 停止DMA传输
RxNum2=RxBufferSize-__HAL_DMA_GET_COUNTER(&hdma_usart2_rx);//总计数减去未传输的数据个数,得到已经接收的数据个数 __HAL_DMA_GET_COUNTER(&hdma_usart2_rx)获取DMA中未传输的数据个数
flag_idie2=1;// 接受完成标志位置1
}
/* USER CODE END USART2_IRQn 0 */
HAL_UART_IRQHandler(&huart2);
/* USER CODE BEGIN USART2_IRQn 1 */

/* USER CODE END USART2_IRQn 1 */
}

蓝牙HC-05和串口1的数据处理

蓝牙APP 发送  相当于 STM32串口1接受数据  

T1 温度加  T2 温度减  F1 风扇加  F2 风扇减  Z1 制冷片状态翻转 H1 温度上限加  H2 温度上限减  L1 温度下限加  L2 温度下限减

if(flag_idie == 1) //蓝牙串口1接收完成标志
{
flag_idie = 0;//清除接收结束标志位
// 在接收到的数据末尾添加字符串结束符
RxBuffer[RxNum] = '\\0';
if(RxNum == 2) // 应该是2个字符,如"T1"
{
// 根据接收到的命令执行相应操作
if(strstr(RxBuffer, "T1"))
{
temp_set += 0.1;
}
else if(strstr(RxBuffer, "T2"))
{
temp_set -= 0.10;
}
else if(strstr(RxBuffer, "F1"))
{
pwmVal += 100;
if(pwmVal > 999) pwmVal = 999;
}
else if(strstr(RxBuffer, "F2"))
{
pwmVal -= 100;
if(pwmVal < 0) pwmVal = 0;
}
else if(strstr(RxBuffer, "Z1"))
{
refrigeration_sheet = 1 – refrigeration_sheet;
}
else if(strstr(RxBuffer, "H1"))
{
temp_up_limit++;
}
else if(strstr(RxBuffer, "H2"))
{
temp_up_limit–;
}
else if(strstr(RxBuffer, "L1"))
{
temp_down_limit++;
}
else if(strstr(RxBuffer, "L2"))
{
temp_down_limit–;
}
}

////风扇强度
__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3, pwmVal);
// 确保温度上下限合理
if(temp_up_limit <= temp_down_limit)
{
// 自动调整,保持至少1度差值
if(strstr(RxBuffer, "H2"))
{
temp_down_limit = temp_up_limit – 1;
}
else if(strstr(RxBuffer, "L1"))
{
temp_up_limit = temp_down_limit + 1;
}
}
//pwmVal=extractKeyValue(RxBuffer,"pwm");
////风扇强度
//__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3, pwmVal);
//
//refrigeration_sheet=extractKeyValue(RxBuffer,"ref");
//if(refrigeration_sheet!=1) refrigeration_sheet=0;
//发给语音模块
//HAL_UART_Transmit_DMA(&huart2, RxBuffer,RxNum);
//发给手机

//HAL_UART_Transmit_DMA(&huart1, RxBuffer,RxNum);
//HAL_Delay(10);
RxNum=0;//清除计数
memset(RxBuffer,0,RxBufferSize);
HAL_UART_Receive_DMA(&huart1,RxBuffer,RxBufferSize);//串口通过DMA接受指定长度的数据。
}

蓝牙数据上报

每600ms上报一次数据给蓝牙APP

T25.6F700Z0H30L25 表示温度25.6 风扇强度700 制冷片状态 关 温度上限30  温度下限25 

if(ms-prems_600>=600)
{
////每1s 上报温度 风扇强度 制冷片状态 温度上限 温度下限
printf("T%.1fF%03dZ%dH%dL%d", display_temp,pwmVal,refrigeration_sheet,temp_up_limit,temp_down_limit);
prems_600=ms;
}

每1s发生当前温度给SU-03T语音模块

if(ms-prems_time>=1000)
{
temp = DS18B20_Get_Temp();
display_temp=temp+temp_set;
temp_Reported[0] = 0xAA;
temp_Reported[1] = 0x55;
temp_Reported[2] = 0x01;

// 将90.9分解为整数部分和小数部分
int integer_part = (int)temp; // 取整数部分 = 90
float decimal = temp – integer_part+temp_set; // 取小数部分 = 0.9
int decimal_part = (int)(decimal * 10); // 小数部分转换为整数 = 9

// 将整数部分转换为十六进制并赋值给temp_Reported[3]
temp_Reported[3] = (unsigned char)integer_part; // 90的十六进制 = 0x5A

// 将小数部分赋值给temp_Reported[4]
temp_Reported[4] = (unsigned char)decimal_part; // 9的十六进制 = 0x09

temp_Reported[5] = 0x55;
temp_Reported[6] = 0xAA;
//发送给语音模块
HAL_UART_Transmit_DMA(&huart2, temp_Reported,7);

//发给手机
//HAL_UART_Transmit_DMA(&huart1, temp_Reported,6);
//每1s 上报温度 风扇强度 制冷片状态 温度上限 温度下限
//printf("T%.1fF%03dZ%dH%dL%d", temp+temp_set,pwmVal,refrigeration_sheet,temp_up_limit,temp_down_limit);

prems_time=ms;
}

SU-03T语音模块说命令词发生数据给串口2

串口2接受到数据执行相应的操作 

 SU-03T语音模块使用参考这篇博客

SU-03T语言模块实现串口收发功能-CSDN博客

if(flag_idie2 == 1) //语音模块 串口2接收完成标志
{
if(RxBuffer2[0]==0xAA&&RxBuffer2[1]==0x55&&RxBuffer2[4]==0x55&&RxBuffer2[5]==0xAA)//AA 55 05 01 55 AA
{
if(RxBuffer2[2]==0x05)
{
if(RxBuffer2[3]==0x01)//开制冷片
{
refrigeration_sheet=1;
}
else if(RxBuffer2[3]==0x02)//关制冷片
{
refrigeration_sheet=0;
}
}
else if(RxBuffer2[2]==0x06)//AA 55 06 01 55 AA
{
if(RxBuffer2[3]==0x01)//调大风扇
{
pwmVal=pwmVal+300;
if(pwmVal>=999)
{
pwmVal=999;
}
}
else if(RxBuffer2[3]==0x02)//调小风扇
{
pwmVal=pwmVal-300;
if(pwmVal<=0)
{
pwmVal=0;
}
}
else if(RxBuffer2[3]==0x03)//打开风扇
{
pwmVal=700;
}
else if(RxBuffer2[3]==0x04)//关闭风扇
{
pwmVal=0;
}
}
}
//发给手机
//HAL_UART_Transmit_DMA(&huart1, RxBuffer2,RxNum2);
HAL_Delay(10);
RxNum2=0;//清除计数
flag_idie2 = 0;//清除接收结束标志位
memset(RxBuffer2,0,RxBufferSize);
HAL_UART_Receive_DMA(&huart2,RxBuffer2,RxBufferSize);//串口通过DMA接受指定长度的数据。
}

OLED界面显示函数

/*******************************************************************************
* Function Name : void OLED_Display_Fresh(void)
* Description : OLED刷新显示函数;
* Description : OLED_flag为界面号: 0=>OLED_Start; 1=>OLED_Main; 2=>OLED_Set; 3=>OLED_State
* Input : None
* Output : None
* Return : OLED_Display_Fresh();
*******************************************************************************/
void OLED_Display_Fresh(void)
{

switch(OLED_flag)
{
case 0://*************** 开机界面; **********************************************//
//OLED_Clear();
//OLED_ShowCN(32,0,21);//陈
//OLED_ShowCN(48,0,22);//炳
//OLED_ShowCN(64,0,23);//琴
//OLED_ShowCN(80,0,24);//毕
//OLED_ShowCN(96,0,25);//设
OLED_ShowCN(16,0,26);//智
OLED_ShowCN(32,0,27);//能
OLED_ShowCN(48,0,28);//水
OLED_ShowCN(64,0,29);//杯
OLED_ShowCN(80,0,30);//降
OLED_ShowCN(96,0,31);//温

if(OLED_blink==1)
{
OLED_ShowCN(0,4,16);//按
OLED_ShowStr(16,4, " E", 2);//显示字符串
OLED_ShowCN(32,4,17);//键
OLED_ShowCN(48,4,18);//进
OLED_ShowCN(64,4,11);//入
OLED_ShowCN(80,4,12);//界
OLED_ShowCN(96,4,13);//面
}
else
{
OLED_ShowStr(0,4, " ", 2);
}
//sprintf(pwm_str,"pwmVal=%d ",pwmVal);
//OLED_ShowStr(0,6,pwm_str, 2);
break;
case 1:// ************** 主界面; ************************************************//
if(OLED_main_flag==1)
{
//主界面显示
OLED_ShowCN(16,0,11);
OLED_ShowCN(32,0,12);
OLED_ShowCN(48,0,13);
OLED_ShowCN(64,0,14);
OLED_ShowCN(80,0,15);

OLED_ShowChar(24,2,'>',16);

if(OLED_blink==1)
{
OLED_ShowCN(32,2,37);//空
OLED_ShowCN(48,2,37);
OLED_ShowCN(64,2,37);
OLED_ShowCN(80,2,37);
}
else
{
OLED_ShowCN(32,2,32);//手
OLED_ShowCN(48,2,33);//动
OLED_ShowCN(64,2,34);//模
OLED_ShowCN(80,2,35);//式
}

OLED_ShowCN(32,4,36);//自
OLED_ShowCN(48,4,33);//动
OLED_ShowCN(64,4,34);//模
OLED_ShowCN(80,4,35);//式

OLED_ShowCN(32,6,47);//参
OLED_ShowCN(48,6,48);//数
OLED_ShowCN(64,6,49);//设
OLED_ShowCN(80,6,50);//定

}

else if(OLED_main_flag==2)
{
//主界面显示
OLED_ShowCN(16,0,11);
OLED_ShowCN(32,0,12);
OLED_ShowCN(48,0,13);
OLED_ShowCN(64,0,14);
OLED_ShowCN(80,0,15);

OLED_ShowCN(32,2,32);//手
OLED_ShowCN(48,2,33);//动
OLED_ShowCN(64,2,34);//模
OLED_ShowCN(80,2,35);//式

OLED_ShowChar(24,4,'>',16);
if(OLED_blink==1)
{
OLED_ShowCN(32,4,37);
OLED_ShowCN(48,4,37);
OLED_ShowCN(64,4,37);
OLED_ShowCN(80,4,37);
}
else
{
OLED_ShowCN(32,4,36);//自
OLED_ShowCN(48,4,33);//动
OLED_ShowCN(64,4,34);//模
OLED_ShowCN(80,4,35);//式
}
OLED_ShowCN(32,6,47);//参
OLED_ShowCN(48,6,48);//数
OLED_ShowCN(64,6,49);//设
OLED_ShowCN(80,6,50);//定
}

else if(OLED_main_flag==3)
{
//主界面显示
OLED_ShowCN(16,0,11);
OLED_ShowCN(32,0,12);
OLED_ShowCN(48,0,13);
OLED_ShowCN(64,0,14);
OLED_ShowCN(80,0,15);

OLED_ShowCN(32,2,32);//手
OLED_ShowCN(48,2,33);//动
OLED_ShowCN(64,2,34);//模
OLED_ShowCN(80,2,35);//式

OLED_ShowCN(32,4,36);//自
OLED_ShowCN(48,4,33);//动
OLED_ShowCN(64,4,34);//模
OLED_ShowCN(80,4,35);//式

OLED_ShowChar(24,6,'>',16);
if(OLED_blink==1)
{
OLED_ShowCN(32,6,37);
OLED_ShowCN(48,6,37);
OLED_ShowCN(64,6,37);
OLED_ShowCN(80,6,37);
}
else
{
OLED_ShowCN(32,6,47);//参
OLED_ShowCN(48,6,48);//数
OLED_ShowCN(64,6,49);//设
OLED_ShowCN(80,6,50);//定

}

}
break;
case 2:// ************** 手动 模式; ************************************************//
OLED_ShowCN(32,0,32);//手
OLED_ShowCN(48,0,33);//动
OLED_ShowCN(64,0,34);//模
OLED_ShowCN(80,0,35);//式

OLED_ShowCN(0,2,38);//温
OLED_ShowCN(16,2,39);//度
if(OLED_set==1&&OLED_blink==1)
{
OLED_ShowStr(40,2," ", 2);
sprintf(pwm_str,":%d ",pwmVal);
OLED_ShowStr(65,4,pwm_str, 2);
sprintf(refrigeration_sheet_str,":%d ",refrigeration_sheet);
OLED_ShowStr(49,6,refrigeration_sheet_str, 2);
}
else if(OLED_set==1&&OLED_blink==0)
{
sprintf(temp_str,":%0.1f",display_temp);
OLED_ShowStr(33,2,temp_str, 2);
}

OLED_ShowCN(0,4,40);//风
OLED_ShowCN(16,4,41);//扇
OLED_ShowCN(32,4,42);//风
OLED_ShowCN(48,4,43);//扇
if(OLED_set==2&&OLED_blink==1)
{
OLED_ShowStr(65+8-1,4," ", 2);
sprintf(temp_str,":%0.1f",display_temp);
OLED_ShowStr(33,2,temp_str, 2);
sprintf(refrigeration_sheet_str,":%d ",refrigeration_sheet);
OLED_ShowStr(49,6,refrigeration_sheet_str, 2);
}
else if(OLED_set==2&&OLED_blink==0)
{
sprintf(pwm_str,":%d ",pwmVal);
OLED_ShowStr(65,4,pwm_str, 2);
}

OLED_ShowCN(0,6,44);//制
OLED_ShowCN(16,6,45);//冷
OLED_ShowCN(32,6,46);//片
if(OLED_set==3&&OLED_blink==1)
{
OLED_ShowStr(49+8-1,6," ", 2);
sprintf(temp_str,":%0.1f",display_temp);
OLED_ShowStr(33,2,temp_str, 2);
sprintf(pwm_str,":%d ",pwmVal);
OLED_ShowStr(65,4,pwm_str, 2);
}
else if(OLED_set==3&&OLED_blink==0)
{
sprintf(refrigeration_sheet_str,":%d ",refrigeration_sheet);
OLED_ShowStr(49,6,refrigeration_sheet_str, 2);
}
if(OLED_set==0)
{
sprintf(temp_str,":%0.1f",display_temp);
OLED_ShowStr(33,2,temp_str, 2);
sprintf(pwm_str,":%d ",pwmVal);
OLED_ShowStr(65,4,pwm_str, 2);
sprintf(refrigeration_sheet_str,":%d ",refrigeration_sheet);
OLED_ShowStr(49,6,refrigeration_sheet_str, 2);
}

break;
case 3:// ************** 自动 模式; ************************************************//
OLED_ShowCN(32,0,36);//自
OLED_ShowCN(48,0,33);//动
OLED_ShowCN(64,0,34);//模
OLED_ShowCN(80,0,35);//式

OLED_ShowCN(0,2,38);//温
OLED_ShowCN(16,2,39);//度
sprintf(temp_str,":%0.1f",display_temp);
OLED_ShowStr(33,2,temp_str, 2);

OLED_ShowCN(0,4,40);//风
OLED_ShowCN(16,4,41);//扇
OLED_ShowCN(32,4,42);//风
OLED_ShowCN(48,4,43);//扇
sprintf(pwm_str,":%d ",pwmVal);
OLED_ShowStr(65,4,pwm_str, 2);

OLED_ShowCN(0,6,44);//制
OLED_ShowCN(16,6,45);//冷
OLED_ShowCN(32,6,46);//片
sprintf(refrigeration_sheet_str,":%d ",refrigeration_sheet);
OLED_ShowStr(49,6,refrigeration_sheet_str, 2);
break;
case 4:// ************** 参数 设定; ************************************************//
OLED_ShowCN(0,0,38);//温
OLED_ShowCN(16,0,39);//度
OLED_ShowCN(32,0,51);//上
OLED_ShowCN(48,0,53);//限
if(OLED_set==1&&OLED_blink==1)
{
OLED_ShowStr(65+8,0," ", 2);
sprintf(temp_str,":%d",temp_down_limit);
OLED_ShowStr(65,2,temp_str, 2);
}
else if(OLED_set==1&&OLED_blink==0)
{
sprintf(temp_str,":%d",temp_up_limit);
OLED_ShowStr(65,0,temp_str, 2);
sprintf(temp_str,":%d",temp_down_limit);
OLED_ShowStr(65,2,temp_str, 2);
}
OLED_ShowCN(0,2,38);//温
OLED_ShowCN(16,2,39);//度
OLED_ShowCN(32,2,52);//下
OLED_ShowCN(48,2,53);//限
if(OLED_set==2&&OLED_blink==1)
{
sprintf(temp_str,":%d",temp_up_limit);
OLED_ShowStr(65,0,temp_str, 2);
OLED_ShowStr(65+8,2," ", 2);
}
else if(OLED_set==2&&OLED_blink==0)
{
sprintf(temp_str,":%d",temp_up_limit);
OLED_ShowStr(65,0,temp_str, 2);
sprintf(temp_str,":%d",temp_down_limit);
OLED_ShowStr(65,2,temp_str, 2);
}
if(OLED_set==0)
{
sprintf(temp_str,":%d",temp_up_limit);
OLED_ShowStr(65,0,temp_str, 2);
sprintf(temp_str,":%d",temp_down_limit);
OLED_ShowStr(65,2,temp_str, 2);
}

break;
default:break;
}

}

这里就不过多赘述了 代码也给了 重点还是串口收发和代码逻辑上 下一篇是蓝牙APP的制作

赞(0)
未经允许不得转载:网硕互联帮助中心 » HC-05蓝牙与STM32进行APP通信实战教程---第三期stm32利用cubemx生成代码----STM32部分完结篇
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!