实战篇:GY-906红外测温模块 + 万年历(定时器计数中断版本) -STM32篇

 本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发

       向上代码兼容GD32F450ZGT6中使用

       后续项目主要在下面该专栏中发布:

https://blog.csdn.net/qq_62316532/category_12608431.html?spm=1001.2014.3001.5482

       感兴趣的点个关注收藏一下吧!

       电机驱动开发可以跳转:

GD32F103RCT6/GD32F303RCT6-实战项目-无刷电机驱动(1)_gd32f103rct6例程-CSDN博客

       BMS电源系统开发可以跳转:暂未放链接

演示视频:

GY-906+数字万年历演示视频

介绍

从本小节开始将会对常用模块进行组合和小作业测试的方式去进行教学,博客后续发表的方式为:stm32版本+GD32版本

本节讲的是GY906红外测温模块的使用以及数字万年历的使用,其中数字万年历采用定时器计数中断制作。

GY-906 是一种常用的红外温度测量模块,广泛应用于非接触式的温度检测场景。这种模块的核心元件通常是 MLX90614 红外温度传感器芯片,由 Melexis 公司生产。MLX90614 芯片结合了先进的红外传感技术和信号处理电路,能够测量物体的表面温度而无需直接接触。

使用资源介绍

stm32f103c8t6:

两路I2C,一个通用定时器

1.其中PB8、PB9用于I2C和OLED显示屏通讯,用于显示数据信息

2.PB8、PA15用于I2C和GY-906模块通讯获取红外温度值

3.定时器3用于产生500Ms的中断,叠加2次后使得秒数+1,作为万年历的时基。

定时器3初始化:

定时器用于时基的产生,驱动我们本次万年历的时钟基础。

//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr,u16 psc)
{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //TIM3时钟使能//定时器TIM3初始化,简单进行定时器初始化,设置 预装载值 和 分频系数TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断//中断优先级NVIC设置NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器TIM_Cmd(TIM3, ENABLE);  //使能TIMx					 
}

对其进行初始化以产生500Ms的中断:

 TIM3_Int_Init(4999,7199);//10Khz的计数频率,计数到5000为500ms

GY-906模块的初始化

参考商家链接:
https://pan.baidu.com/s/1V4IX0PKG8vDOionICghSTwicon-default.png?t=N7T8https://pan.baidu.com/s/1V4IX0PKG8vDOionICghSTw

理后如下:

GY-906.c文件:
#include "GY-906.h"/*******************************************************************************
* Function Name  : Mlx90614_Configuration
* Description    : Mlx90614_Configuration
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void Mlx96014_Configuration(void)
{GPIO_InitTypeDef  GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_15;//SCLGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8;//SDAGPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_Init(GPIOA,&GPIO_InitStructure);SDA_H;SCL_H; 
}/*******************************************************************************
* Function Name  : SMBus_StartBit
* Description    : 在SMBus上生成START条件
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void SMBus_StartBit(void)
{SDA_H;               // Set SDA line SMBus_Delay(1);      // Wait a few microseconds SCL_H;               // Set SCK line  SMBus_Delay(5);      // Generate bus free time between StopSDA_L;               // Clear SDA lineSMBus_Delay(10);     // Hold time after (Repeated) Start// Condition. After this period, the first clock is generated.//(Thd:sta=4.0us min)SCL_L;               // Clear SCK lineSMBus_Delay(2);      // Wait a few microseconds
}/*******************************************************************************
* Function Name  : SMBus_StopBit
* Description    : Generate STOP condition on SMBus
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/void SMBus_StopBit(void)
{SCL_L;                // Clear SCK lineSMBus_Delay(5);       // Wait a few microsecondsSDA_L;                // Clear SDA lineSMBus_Delay(5);       // Wait a few microsecondsSCL_H;                // Set SCK lineSMBus_Delay(10);      // Stop condition setup time(Tsu:sto=4.0us min)SDA_H;                // Set SDA line
}/*******************************************************************************
* Function Name  : SMBus_SendByte
* Description    : 在SMBus上发送一个字节
* Input          : Tx_buffer
* Output         : None
* Return         : None
*******************************************************************************/
u8 SMBus_SendByte(u8 Tx_buffer)
{u8        Bit_counter;u8        Ack_bit;u8        bit_out;for(Bit_counter=8; Bit_counter; Bit_counter--){if (Tx_buffer&0x80){bit_out=1;       // If the current bit of Tx_buffer is 1 set bit_out}else{bit_out=0;      // else clear bit_out}SMBus_SendBit(bit_out);           // Send the current bit on SDATx_buffer<<=1;                    // Get next bit for checking}Ack_bit=SMBus_ReceiveBit();           // Get acknowledgment bitreturn        Ack_bit;
}/*******************************************************************************
* Function Name  : SMBus_SendBit
* Description    : Send a bit on SMBus
* Input          : bit_out
* Output         : None
* Return         : None
*******************************************************************************/
void SMBus_SendBit(u8 bit_out)
{if(bit_out==0){SDA_L;   }else{SDA_H;}SMBus_Delay(2);                            // Tsu:dat = 250ns minimumSCL_H;                                     // Set SCK lineSMBus_Delay(10);                           // High Level of Clock PulseSCL_L;                                     // Clear SCK lineSMBus_Delay(10);                           // Low Level of Clock Pulse
//        SMBUS_SDA_H();                       // Master release SDA line ,return;
}
/*******************************************************************************
* Function Name  : SMBus_ReceiveBit
* Description    : 在SMBus上接收一位
* Input          : None
* Output         : None
* Return         : Ack_bit
*******************************************************************************/
u8 SMBus_ReceiveBit(void)
{u8 Ack_bit;SDA_H;             //?????????,????SCL_H;             // Set SCL lineSMBus_Delay(2);    // High Level of Clock Pulseif (SMBUS_SDA_PIN){Ack_bit=1;}else{Ack_bit=0;}SCL_L;                    // Clear SCL lineSMBus_Delay(4);           // Low Level of Clock Pulsereturn   Ack_bit;
}
/*******************************************************************************
* Function Name  : SMBus_ReceiveByte
* Description    : 在SMBus上接收一个字节
* Input          : ack_nack
* Output         : None
* Return         : RX_buffer
*******************************************************************************/
u8 SMBus_ReceiveByte(u8 ack_nack)
{u8        RX_buffer;u8        Bit_Counter;for(Bit_Counter=8; Bit_Counter; Bit_Counter--){if(SMBus_ReceiveBit())         // Get a bit from the SDA line{RX_buffer <<= 1;           // If the bit is HIGH save 1  in RX_bufferRX_buffer |=0x01;}else{RX_buffer <<= 1;           // If the bit is LOW save 0 in RX_bufferRX_buffer &=0xfe;}}SMBus_SendBit(ack_nack);           // Sends acknowledgment bitreturn RX_buffer;
}/*******************************************************************************
* Function Name  : SMBus_Delay
* Description    : 1us
* Input          : time
* Output         : None
* Return         : None
*******************************************************************************/
void SMBus_Delay(u16 time)
{u16 i, j;for (i=0; i<4; i++){for (j=0; j<time; j++);}
}/******************************************************************************** Function Name  : SMBus_ReadMemory* Description    : 从RAM/EEPROM读取数据* Input          : slaveAddress, command* Output         : None* Return         : Data
*******************************************************************************/
u16 SMBus_ReadMemory(u8 slaveAddress, u8 command)
{u16 data;               // Data storage (DataH:DataL)u8 Pec;                 // PEC byte storageu8 DataL=0;             // Low data byte storageu8 DataH=0;             // High data byte storageu8 arr[6];              // Buffer for the sent bytesu8 PecReg;              // Calculated PEC byte storageu8 ErrorCounter;        // Defines the number of the attempts for communication with MLX90614ErrorCounter=0x00;                                // Initialising of ErrorCounterslaveAddress <<= 1;        //2-7???????do{
repeat:SMBus_StopBit();                //If slave send NACK stop comunication--ErrorCounter;                 //Pre-decrement ErrorCounterif(!ErrorCounter)               //ErrorCounter=0?{break;                      //Yes,go out from do-while{}}SMBus_StartBit();               //Start conditionif(SMBus_SendByte(slaveAddress))//Send SlaveAddress ???Wr=0????????{goto  repeat;               //Repeat comunication again}if(SMBus_SendByte(command))     //Send command{goto    repeat;             //Repeat comunication again}SMBus_StartBit();                //Repeated Start conditionif(SMBus_SendByte(slaveAddress+1))  //Send SlaveAddress ???Rd=1????????{goto        repeat;           //Repeat comunication again}DataL = SMBus_ReceiveByte(ACK);   //Read low data,master must send ACKDataH = SMBus_ReceiveByte(ACK);   //Read high data,master must send ACKPec = SMBus_ReceiveByte(NACK);    //Read PEC byte, master must send NACKSMBus_StopBit();                  //Stop conditionarr[5] = slaveAddress;        arr[4] = command;arr[3] = slaveAddress+1;         //Load array arrarr[2] = DataL;                 arr[1] = DataH;                arr[0] = 0;                   PecReg=PEC_Calculation(arr);     //Calculate CRC}while(PecReg != Pec);                //If received and calculated CRC are equal go out from do-while{}data = (DataH<<8) | DataL;       //data=DataH:DataLreturn data;
}/*******************************************************************************
* Function Name  : PEC_calculation
* Description    : 计算接收字节的PEC
* Input          : pec[]
* Output         : None
* Return         : pec[0]-this byte contains calculated crc value
*******************************************************************************/
u8 PEC_Calculation(u8 pec[])
{u8         crc[6];u8        BitPosition=47;u8        shift;u8        i;u8        j;u8        temp;do{/*Load pattern value 0x000000000107*/crc[5]=0;crc[4]=0;crc[3]=0;crc[2]=0;crc[1]=0x01;crc[0]=0x07;/*Set maximum bit position at 47 ( six bytes byte5...byte0,MSbit=47)*/BitPosition=47;/*Set shift position at 0*/shift=0;/*Find first "1" in the transmited message beginning from the MSByte byte5*/i=5;j=0;while((pec[i]&(0x80>>j))==0 && i>0){BitPosition--;if(j<7){j++;}else{j=0x00;i--;}}/*End of while *//*Get shift value for pattern value*/shift=BitPosition-8;/*Shift pattern value */while(shift){for(i=5; i<0xFF; i--){if((crc[i-1]&0x80) && (i>0)){temp=1;}else{temp=0;}crc[i]<<=1;crc[i]+=temp;}/*End of for*/shift--;}/*End of while*//*Exclusive OR between pec and crc*/for(i=0; i<=5; i++){pec[i] ^=crc[i];}/*End of for*/}while(BitPosition>8); /*End of do-while*/return pec[0];
}/******************************************************************************** Function Name  : SMBus_ReadTemp* Description    : 计算并返回温度* Input          : None* Output         : None* Return         : SMBus_ReadMemory(0x00, 0x07)*0.02-273.15
*******************************************************************************/
float SMBus_ReadTemp(void)
{   return SMBus_ReadMemory(SA, RAM_ACCESS|RAM_TOBJ1)*0.02-273.15;//绝对零度
}
/*********************************END OF FILE*********************************/

在主函数中进行初始化:

Mlx96014_Configuration();

万年历设计:

首先定义本次使用到的变量:

u8 sec = 0;
u8 min = 10;
u8 hour=23;
u8 date = 19;
u8 month = 6;
u16 year = 2024;
u8 day_max=31;

其中day_max为最大天数,用于确定当前月份的最大天数是多少

判断内容如下:

 if(month==2){day_max=28;}else if(month==4||month==6||month==9||month==11){day_max=30;}else{day_max=31;}

根据不同月份,去对天数进行判断,

一年一共有365天或者366天,平年有365天,闰年有366天,闰年每隔4年一次。

平年的2月是28天,闰年2月是29天。

4月、6月、9月、11月各是30天。

1月、3月、5月、7月、8月、10月、12月各是31天。

接下来就是在定时器中断函数中对万年历的基础代码进行编写:

 if(i==2){i=0;sec++;if(sec>=60){sec=0;min++;if(min>=60){min=0;hour++;if(hour>=24){hour=0;date++;if(date>=day_max){date=0;month++;if(month>=12){year++;									 }}}}}}

在定时器500Ms的中断时间作为基础时间基数的情况下,通过秒数的累加,去驱动整个万年历进行工作

主函数

主函数中要做的就很简单,因为逻辑代码在中断里面已经做完了,所以主函数中只需要完成OLED的显示和基础功能的初始化即可!

       OLED_ShowNum(		5,	15,year,4,12);OLED_ShowString(30,	15,"/",12);//6*12 “ABC”				OLED_ShowNum(		35,	15,month,2,12);OLED_ShowString(50,	15,"/",12);//6*12 “ABC”	OLED_ShowNum(		55,	15,date,2,12);OLED_ShowNum(	15,	25,hour,2,12);OLED_ShowString(30,	25,"/",12);//6*12 “ABC”	OLED_ShowNum(		35,	25,min,2,12);OLED_ShowString(	50,	25,"/",12);//6*12 “ABC”	OLED_ShowNum(		55,	25,sec,2,12);OLED_ShowString(0,0,Temperatures,16);//6*12 “ABC”	OLED_Refresh();

总结:

经过本小结,希望大家能够掌握GY-906的使用,以及用stm32所提供的定时器去完成对万年历的设计!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/32413.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第10章 启动过程组 (制定项目章程)

第10章 启动过程组 9.1制定项目章程&#xff0c;在第三版教材第356~360页&#xff1b; 文字图片音频方式 视频12 第一个知识点&#xff1a;主要输出 1、项目章程&#xff08;重要知识点&#xff09; 项目目的 为了稳定与发展公司的客户群(抽象&#xff0c;非具体) 可测量的项目…

探索Agent AI智能体的未来

随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;Agent AI智能体正成为一种改变世界的新力量。这些智能体不仅在当前的技术领域中发挥着重要作用&#xff0c;而且在未来将以更深远的影响改变我们的生活、工作和社会结构。本文将探讨Agent AI智能体的现状、潜…

微信小程序-伪类选择器

一.伪类选择器 结构伪类常见书写方式&#xff1a; 第一类&#xff1a;找第几个孩子 1. :first-child 找第一个孩子2. :last-child 找最后一个孩子3. :nth-child()&#xff0c;正着找数字&#xff1a;写数字几就是找第几个孩子&#xff0c;2n或者even:找偶数2n1或者o…

“论微服务架构及其应用”写作框架,软考高级,系统架构设计师

论文真题 论微服务架构及其应用近年来&#xff0c;随着互联网行业的迅猛发展&#xff0c;公司或组织业务的不断扩张&#xff0c;需求的快速变化以及用户量的不断增加&#xff0c;传统的单块&#xff08;Monolithic&#xff09;软件架构面临着越来越多的挑战&#xff0c;已逐渐…

一个关于空格的Sql Server面试题

引子 先上题目&#xff1a; 回答下面sql 的输出结果 declare s1 varchar(10) declare s2 varchar(10) set s1a b set s2a b if s1s2 select true 答案是 true 那么上面的 s1 和 s2 是否相等的呢&#xff1f; 我们再看看下面的sql declare s1 varchar(10) declare s2 …

【建议收藏】Android中高级大厂面试源码秘籍,为你备战2021金三银四,直通大厂

首先来说下为什么要读源码&#xff0c;有学习源码的必要吗&#xff1f; 为什么要阅读源码&#xff1f; 关于为什么阅读和学习源码&#xff0c;我个人认为可能有以下几点&#xff1a; &#xff08;一&#xff09;吊打面试官&#xff0c;应对面试 为了找到更好的工作&#xff…

异地局域网纯软件组网如何设置?

在现代社会中&#xff0c;随着企业的不断扩张和分布&#xff0c;异地办公成为一种常见的工作模式。随之而来的是&#xff0c;如何实现异地局域网的组网设置成为了一个挑战。在这种情况下&#xff0c;采用纯软件组网方案是一种有效的解决方案。本文将介绍异地局域网纯软件组网设…

双非本,3年时间从外包到阿里P6(Android岗),看我是怎么逆袭成功的?

而在小公司&#xff0c;因为我也在小公司呆过&#xff0c;所以我有最直接的感受。整个部门技术人员没几个&#xff0c;我又大学刚毕业&#xff0c;带我的人&#xff0c;问啥啥不会&#xff0c;只有一个大佬&#xff0c;跳槽来的&#xff0c;是我们技术总监&#xff0c;有问题谁…

python数据分析案例-信用卡违约预测分析

一、研究背景和意义 信用卡已经成为现代社会中人们日常生活中不可或缺的支付工具&#xff0c;它不仅为消费者提供了便利&#xff0c;还为商家提供了更广泛的销售渠道。然而&#xff0c;随着信用卡的普及和使用量的增加&#xff0c;信用卡违约问题逐渐成为金融机构面临的重要挑…

摄像头画面显示于unity场景

&#x1f43e; 个人主页 &#x1f43e; &#x1faa7;阿松爱睡觉&#xff0c;横竖醒不来 &#x1f3c5;你可以不屠龙&#xff0c;但不能不磨剑&#x1f5e1; 目录 一、前言二、UI画面三、显示于场景四、结语 一、前言 由于标题限制&#xff0c;这篇文章主要是讲在unity中调用摄…

深入讲解C++基础知识(一)

目录 一、基本内置类型1. 类型的作用2. 分类3. 整型3.1 内存描述及查询3.2 布尔类型 —— bool3.3 字符类型 —— char3.4 其他整型 4. 有符号类型和无符号类型5. 浮点型6. 如何选择类型7. 类型转换7.1 自动类型转换7.2 强制类型转换7.3 类型转换总结 8. 类型溢出8.1 注意事项 …

机器学习好神奇,来看看Lasso的超参数调整与模型选择

目录 一、什么是机器学习&#xff1f;二、稀疏建模介绍三、Lasso回归简介四、Lasso超参数调整与模型选择 一、什么是机器学习&#xff1f; 机器学习是一种人工智能技术&#xff0c;它使计算机系统能够从数据中学习并做出预测或决策&#xff0c;而无需明确编程。它涉及到使用算…

Android面试题之动画+事件处理篇

1、Android 中的动画有哪几类 帧动画、补间动画、属性动画 2、动画能组合在一起使用么&#xff1f; 可以将动画组合在一起使用AnimatorSet&#xff0c; AnimatorSet.play() 播放当前动画的同时可以 .with() &#xff1a;将现有动画和传入的动画同时执行 .after() &#xff1a…

通过开放解析智能分块提高 RAG 性能

如果要使用大型语言模型 &#xff08;&#xff09;LLMs 实现生成式 AI 解决方案&#xff0c;则应考虑使用检索增强生成 &#xff08;RAG&#xff09; 的策略来生成上下文感知提示LLM。在启用 LLM RAG 的预生产管道中发生的一个重要过程是删除文档文本&#xff0c;以便仅将文档中…

[数据集][目标检测]药片药丸检测数据集VOC+YOLO格式152张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;152 标注数量(xml文件个数)&#xff1a;152 标注数量(txt文件个数)&#xff1a;152 标注类别…

听说你还不会用Dagger2?Dagger2 For Android最佳实践教程

Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(TAG,chef.cook()); } } 可以看到&#xff0c;在使用Dagger2的时候&#xff0c;使用者的代码会变得非常简洁。但是&#…

如何用好swoole/webman/workerman/hyperf呢

Webman框架的依赖 "require": { "php": ">7.2", "workerman/webman-framework": "^1.5.0",// "monolog/monolog": "^2.0" }, 依赖的核心框架也是很久的了 webman-framework的核心依赖 &q…

分布式架构的优势与实现

目录 前言1. 什么是分布式架构1.1 分布式架构的定义1.2 分布式架构的基本原理 2. 分布式架构的优势2.1 可扩展性2.2 容错性和高可用性2.3 性能优化2.4 灵活性和可维护性 3. 分布式架构的实现方法3.1 服务拆分3.1.1 功能拆分3.1.2 垂直拆分3.1.3 水平拆分 3.2 数据分布与存储3.2…

java—Mybatis缓存

缓存的作用 缓存(cache&#xff09;的作用是为了减轻数据库的压力&#xff0c;提高查询性能。 为什么使用缓存 mysql数据库保存的数据均在硬盘中&#xff0c;CPU是不会直接和硬盘进行交互的&#xff0c;因为硬盘的数据传输率很低&#xff0c;而CPU的数据传输率很高, CPU和内存直…