程序架构
第一部分:所用到模块的初始化
第二部分:中断部分。利用定时中断实现呼吸灯、RTC显示时间、动态图片切换、超时检测以及息屏等功能
第三部分:主逻辑循环部分。采用的是状态机扫描的方式进行的,根据按键控制页编号变量,然后页编号控制相应的功能。
具体程序如下:
主逻辑循环部分:
int a = 10;
int main(void)
{
u8 key = 0;
function_init();
/*开机功能*/
page_open();
a++;
while(1)
{
key = fun_key_scan();
//按键控制页编号变量
if(key == KEY_Right && key_ok_flag==0)
{
page_flag = 1;
timer_buff[7] = 0; //息屏计时开始
OLED_clear();
if(!oled_sta_flag) //不息屏状态
{
page++;
if(page>6)
{
page = 1;
}
}
else
{
OLED_writeByte(0xAF,OLED_CMD);
oled_sta_flag = 0;
}
}
else if(key == KEY_Left && key_ok_flag==0)
{
page_flag = 1;
timer_buff[7] = 0; //息屏计时开始
OLED_clear();
if(!oled_sta_flag)
{
page--;
if(page<1)
{
page = 6;
}
}
else
{
OLED_writeByte(0xAF,OLED_CMD);
oled_sta_flag = 0;
}
}
//页编号变量控制界面显示
switch(page)
{
case 1: function_page1();break;
case 2: function_page2(key);break;
case 3: function_page3();break;
case 4: function_page4();break;
case 5: function_page5();break;
case 6: function_page6();break;
}
}
return 0;
}
中断部分:
/***********************************************
*函数名 :TIM1_BRK_TIM9_IRQHandler
*函数功能 :TIM9中断服务函数
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
u32 timer_buff[10];
u8 pic_n = 0;
RTC_t val;
u8 heart_pic_n = 0;
u8 oled_sta_flag = 0;
void TIM1_BRK_TIM9_IRQHandler(void)
{
//判断是定时器9的更新中断信号触发
if(TIM9->SR & (1<<0))
{
//清除中断标志位
TIM9->SR &= ~(1<<0);
//紧急事件
timer_buff[1]++;
timer_buff[2]++;
timer_buff[3]++;
timer_buff[4]++;
timer_buff[5]++;
timer_buff[6]++;
timer_buff[7]++;
//运行指示灯500ms
if(timer_buff[1] >= 500)
{
timer_buff[1] = 0;
LED_OVERTURN;
}
//RTC显示时间 1000ms
if(timer_buff[2] >= 1000)
{
timer_buff[2] = 0;
//在设置时间模式下暂听获取时间
if(key_ok_flag==0 && (page==2 || page==3))
{
val = get_time();
fun_flag = 1;
}
}
//timer_buff[3]== 100解锁按键标志位
if(timer_buff[3] == 100)
{
MOTOR_VAL = 0;
}
//动态图片切换
const u8 *pics[] = {pic_0,pic_1,pic_2,pic_3,pic_4,pic_5,pic_6};
if(timer_buff[4] >= 50)
{
if(page==1)
{
pic_n++;
if(pic_n>=102)
{
pic_n=0;
}
fun_flag = 1;
}
//oled_dis_pic(0,1,64,64,tkr64x64[pic_n]);
timer_buff[4] = 0;
}
//心率开始5秒失败退出时间定时
if(timer_buff[5] == 5000)
{
}
//心率动态图
if(timer_buff[6] == 300)
{
if(page == 4)
{
heart_pic_n++;
if(heart_pic_n>1)
{
heart_pic_n=0;
}
fun_flag = 1;
}
timer_buff[6] = 0;
}
//10s息屏
if(timer_buff[7] >= 10000)
{
if(page !=4 && page != 5 && key_ok_flag==0)
{
OLED_writeByte(0xAE,OLED_CMD);
oled_sta_flag = 1;
}
timer_buff[7] = 0;
}
}
}
每页功能模块部分:
#include "main.h" // Device header
u8 page_flag = 1;
u8 fun_flag = 1;
u8 key_ok_flag = 0;
u8 page = 0;
RTC_t time = {2024,4,17,3,15,30,45};
/***********************************************
*函数名 :function_init
*函数功能 :初始haul配置
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
void function_init(void)
{
NVIC_SetPriorityGrouping(5); //抢占2位 响应2位
led_init(); //LED灯初始化配置
usart1_init(115200); //串口初始化
tim2_ch3_pwm_motor(); //振动电机初始化
fun_key_init(); //五方向按键
OLED_init(); //OLED初始化
RTC_init(time); //RTC初始化
sht20_init(); //SHT20初始化
Hp_6_init(); //HP6初始化
MPU6050_init(); //MPU6050初始化配置
tim9_interrupt_ms(1);
}
/***********************************************
*函数名 :page_open
*函数功能 :开机界面
*函数参数 :无
*函数返回值:无
*函数描述 :
************************************************/
void page_open(void)
{
timer_buff[3] = 101;
oled_dis_pic(0,2,128,64,open_pic);
MOTOR_VAL = 1000;
tim11_delay_ms(500);
MOTOR_VAL = 0;
OLED_clear();
page++;
}
/***********************************************
*函数名 :function_page1
*函数功能 :1号页功能
*函数参数 :无
*函数返回值:无
*函数描述 :动态图
************************************************/
void function_page1(void)
{
//只执行一次的程序
if(page_flag == 1)
{
oled_dis_str(3,70,"信盈达",16);
page_flag = 0;
}
//执行多次高刷程序
if(fun_flag == 1)
{
oled_dis_pic(0,2,64,64,(u8 *)(tkr64x64+pic_n));
fun_flag = 0;
}
}
/***********************************************
*函数名 :function_page2
*函数功能 :2号页功能
*函数参数 :无
*函数返回值:无
*函数描述 :时间显示
************************************************/
void function_page2(u8 key)
{
u8 buff[30] = {0};
//只执行一次程序
if(page_flag)
{
timer_buff[2] = 1000; //到此页面马上获取时间显示
printf("你好,第二页\r\n");
page_flag = 0;
}
//执行多次高刷程序
if(fun_flag == 1 && key_ok_flag==0)
{
//转换时间成字符串
sprintf((char *)buff,"%d.%d.%d ",val.year,val.mon,val.day);
oled_dis_str(1,30,buff,16);
sprintf((char *)buff,"%02d:%02d:%02d",val.h,val.m,val.s);
oled_dis_str(3,0,buff,24);
sprintf((char *)buff,"week:%d",val.week);
oled_dis_str(6,40,buff,16);
fun_flag = 0;
}
//垂直界面进出设置模式
static u8 set_list = 0;
static RTC_t t_val;
if(key == KEY_OK)
{
key_ok_flag = !key_ok_flag;
OLED_clear();
//进入到设置界面
if(key_ok_flag == 1)
{
set_list = 0;
//只显示时间
sprintf((char *)buff,"%02d:%02d:%02d",val.h,val.m,val.s);
oled_dis_str(2,set_list,buff,24);
oled_dis_str(5,set_list,"--",24);
t_val = val;
printf("获取原始时间\r\n");
}
//退出设置界面
if(key_ok_flag == 0)
{
//如果没有修改时间值,继续获取RTC原本运行时间
if(t_val.h!=val.h || t_val.m!=val.m || t_val.s!=val.s)
{
set_time(val);
}
timer_buff[2] = 1000; //马上获取时间显示
}
}
//定位更改的时间(时 分 秒)
else if(key_ok_flag==1 && key == KEY_Right)
{
oled_dis_str(5,set_list," ",24);
set_list+=48;
if(set_list>96) {set_list=0;}
oled_dis_str(5,set_list,"--",24);
}
else if(key_ok_flag==1 && key == KEY_Left)
{
oled_dis_str(5,set_list," ",24);
set_list-=48;
if(set_list>200)
{
set_list = 96;
}
oled_dis_str(5,set_list,"--",24);
}
//根据定位调整数值 上调
else if(key_ok_flag==1 && key == KEY_UP)
{
if(set_list==0) //调整小时
{
//时间数据结构体中的小时成员
val.h++;
if(val.h>23) {val.h = 0;}
// sprintf((char *)buff,"%02d",val.h);
// oled_dis_str(2,set_list,buff,24);
}
else if(set_list==48) //调整分钟
{
//时间数据结构体中的分钟成员
val.m++;
if(val.m>59) {val.m = 0;}
// sprintf((char *)buff,"%02d",val.m);
// oled_dis_str(2,set_list,buff,24);
}
else if(set_list==96) //调整秒
{
//时间数据结构体中的秒成员
val.s++;
if(val.s>59) {val.s = 0;}
// sprintf((char *)buff,"%02d",val.s);
// oled_dis_str(2,set_list,buff,24);
}
sprintf((char *)buff,"%02d:%02d:%02d",val.h,val.m,val.s);
oled_dis_str(2,0,buff,24);
}
//根据定位调整数值 下调
else if(key_ok_flag==1 && key == KEY_Down)
{
if(set_list==0) //调整小时
{
//时间数据结构体中的小时成员
val.h--;
if(val.h>200) {val.h = 23;}
sprintf((char *)buff,"%02d",val.h);
oled_dis_str(2,set_list,buff,24);
}
else if(set_list==48) //调整分钟
{
//时间数据结构体中的分钟成员
val.m--;
if(val.m>200) {val.m = 59;}
}
else if(set_list==96) //调整秒
{
//时间数据结构体中的秒成员
val.s--;
if(val.s>200) {val.s = 59;}
}
sprintf((char *)buff,"%02d:%02d:%02d",val.h,val.m,val.s);
oled_dis_str(2,0,buff,24);
}
}
/***********************************************
*函数名 :function_page3
*函数功能 :3号页功能
*函数参数 :无
*函数返回值:无
*函数描述 :温湿度显示
************************************************/
void function_page3(void)
{
TRH_n trh_data;
u8 buff[30];
//只执行一次程序
if(page_flag)
{
if(val.h>=6 && val.h<18) //白天图片
{
oled_dis_pic(0,0,64,64,sun);
}
else //黑天
{
oled_dis_pic(0,0,64,64,night);
}
//关闭心率
HP_6_CloseRate();
page_flag = 0;
}
//执行多次高刷程序
//停留此界面,在这两个时间点变换图片
if((val.h==6 || val.h==18) && val.m==0 && val.s==0)
{
page_flag = 1;
}
//获取温度
trh_data = sht20_rec_val(SHT20_T);
//转换成字符串
sprintf((char *)buff,"T:%0.1f℃",trh_data.t);
//显示字符串
oled_dis_str(1,65,buff,16);
//获取湿度
trh_data = sht20_rec_val(SHT20_RH);
//转换成字符串
sprintf((char *)buff,"RH:%d%%",trh_data.rh);
//显示字符串
oled_dis_str(4,65,buff,16);
}
/***********************************************
*函数名 :function_page4
*函数功能 :4号页功能
*函数参数 :无
*函数返回值:无
*函数描述 :心率测量功能
************************************************/
void function_page4(void)
{
static u8 err;
u8 result = 0;
u8 buff[20];
static u8 old_val;
//只执行一次程序
if(page_flag)
{
//关闭血压
HP_6_Closebp();
//显示界面提示
oled_dis_str(1,80,"心率",16);
oled_dis_str(4,80,"test",16);
oled_dis_pic(0,0,54,54,heart[1]);
//开启心率测量
err = HP_6_OpenRate();
//超时启动报告传感器错误
if(err == 0)
{
oled_dis_str(4,80,"err!",16);
}
page_flag = 0;
}
//执行多次高刷程序
if(fun_flag == 1 && err)
{
oled_dis_pic(0,0,54,54,heart[heart_pic_n]);
fun_flag = 0;
}
//获取心率数据
HP_6_GetRateResult(&result);
if(result!=0 && err && old_val!=result)
{
old_val = result;
sprintf((char *)buff,"%03d",result);
oled_dis_str(4,70,buff,24);
}
}
/***********************************************
*函数名 :function_page5
*函数功能 :5号页功能
*函数参数 :无
*函数返回值:无
*函数描述 :血压测量功能
************************************************/
void function_page5(void)
{
u8 bpResult[2] = {0};
u8 buff[20];
//只执行一次程序
if(page_flag)
{
//关闭心率
HP_6_CloseRate();
//显示测试量血压图片
oled_dis_pic(0,0,54,54,bmp);
oled_dis_str(1,80,"血压",16);
oled_dis_str(3,80,"test",16);
//开启血压
u8 err = HP_6_Openbp();
//超时启动报告传感器错误
if(err == 0)
{
oled_dis_str(3,80,"err!",16);
}
page_flag = 0;
}
//执行多次高刷程序
HP_6_Get_bpResult(bpResult);
if(bpResult[0]!=0 && bpResult[1]!=0)
{
sprintf((char *)buff,"H:%3dPa",bpResult[0]);
oled_dis_str(3,70,buff,16);
sprintf((char *)buff,"L:%3dPa",bpResult[1]);
oled_dis_str(5,70,buff,16);
}
}
/***********************************************
*函数名 :function_page6
*函数功能 :6号页功能
*函数参数 :无
*函数返回值:无
*函数描述 :MPU6050
************************************************/
void function_page6(void)
{
ACCG_t ag;
u8 buff[15];
//只执行一次程序
if(page_flag)
{
//关闭血压
HP_6_Closebp();
page_flag = 0;
}
//执行多次高刷程序
//获取六轴数据
ag = ReadAcceData();
/*显示*/
sprintf((char *)buff,"Ax:%0.1f Gx:%0.1f ",ag.x_Axis ,ag.x_Gxis );
oled_dis_str(0,2,buff,16);
sprintf((char *)buff,"Ay:%0.1f Gy:%0.1f ",ag.y_Axis,ag.y_Gxis);
oled_dis_str(2,2,buff,16);
sprintf((char *)buff,"Az:%0.1f Gz:%0.1f ",ag.z_Axis,ag.z_Gxis);
oled_dis_str(4,2,buff,16);
}