发两期stm32供实验室学习的参考教程,给电力电子实验室的大家
慢慢整理,什么时候整理好什么时候发表
功能:
(1) MCU:本设计是使用STM32F103C8T6为核心,负责本系统软件的整体运行,并且执行智能厨房控制系统的基本功能。
(2) 按键模块:主要负责启动系统。
(3) OLED显示屏:主要负责显示超声波测试的距离、一氧化碳的浓度、探测到锅中的温度。选用0.96寸的OLED显示屏,将温度、一氧化碳浓度等数据显示在OLED屏幕上;
(4) 蜂鸣器模块:主要负责达到设定浓度值时报警。当空气中的一氧化碳浓度达到设定值会启动自动报警功能;
(5) 防空烧模块:主要负责判断是否空烧。该通过超声波部分,先通过模块采集数据,按照dis=(int)count/60.034的算法计算测试到的距离,判断是否空烧。若空烧则及时发出警报并采取相应的措施,以防止烹饪过程中的意外事故;
(6) 继电器模块:主要负责控制炉火的开启关闭。继电器在电路中起着自动调节的作用,同时,它也可以作为一个安全保护装置,确保电路在异常情况下能够安全的切断或转换;
(7) 风扇模块与LED模块:主要负责通风与换气以及LED频闪。当天气热浓度达到预设值时,同时风扇自动打开、蜂鸣器报警、炉火关闭、LED闪红;
(8) 天然气检测模块:主要负责检测当前空间天然气浓度。CH4模块先通过ADC采集数据,然后通过算法得到ADC通道获取的平均值,再通过燃气值计算公式计算燃气值(具体查看MQ-5数据手册),分析空气中的CH4含量,快速准确判断出燃气泄露情况,一旦检测到超过安全范围的气体浓度,系统将发出报警并自动切断天然气供应,以确保用户的安全。
(9) 测温与红外检测模块:主要负责测温与红外测距。该模块通过采用MAX6675进行热电偶冷端补偿和数字化K型热电偶信号,实时监测厨房内的温度和热源,并将数据传输到控制模块,以便进行进一步的分析和控制。
(10) 火力控制模块:主要负责控制炉火的时间。该模块在根据用户设定的需求和菜谱要求,自动控制灶具的开启时间与关闭时间,以实现精确的烹饪控制。
使用模块:
购买清单:
购买建议大家访问淘宝:优信电子!!!靠谱好用又便宜,客服态度又好!!!
平常实验室和工作室采购基本上都在这
使用模块主要有:
K型热电偶 MAX6675模块:
产品说明
MAX6675 是美国MAXIM公司生产的带有冷端补偿、线性校正、热电偶断线检测的12位分辨率串行热电偶模数转换器。
MAX6675的主要特性如下
1、简单的SPI串行口温度值输出。
2、0℃~1024℃的测温范围,转换器温度分辨率为0.25°C。
3、片内冷端补偿。
4、高阻抗差动输入。
5、热电偶断线检测。
6、工作电压范围广3.0~5.5V,工作电流50mA。
7、工作温度范围-20℃~ 85℃。
8、2000V的ESD信号
模块接口:GNDVCC SCKCS SO
供电电压:3~5V DC
MQ-2烟雾传感器:
产品特性:
MQ-2
气体传感器所使用的气敏材料是在清洁空气中电导率较低的二氧化锡(SnO2)。当传感器所处环境中存在可燃气体时,传感器的电导率随空气中可燃气体浓度的增加而增大。对不同种类不同浓度的敏感气体有不同的电阻值,使用简单的电路即可将电导率的变化转换为与该气体浓度相对应的输出信号。可以用于家庭和工厂的气体泄漏监测装置,适宜于液化气、丁烷、丙烷、甲烷、酒精、烟雾等的探测;固定安装孔,使用宽电压LM393比较器,信号干净,波形好,驱动能力强,超15mA,配可调精密电位器调节灵敏度。
产品参数:
工作电压:5VDC
功耗(电流):150mA
输出形式:模拟和数字输出
HC-SR04超声波测距模块:
新版HC-SR04,性能远超老版HC-SR04,US-015;在测距精度高于老版HC-SR04和US-015
的情况下,测距范围更远,可达6米,远超一般超声波测距模块。采用CS-100A超声波测距
SOC芯片,高性能,工业级,宽电压、低价格,成本击穿底价,只有普通超声波测距模块
一半的价格,而性能远超普通超声波测距模块。性能与US-025
A相同,均采用CS100A芯片,接口完全兼容。
OLED显示屏:
OLED显示屏是一种采用有机发光二极管作为发光单元的显示技术,具有自发光、低功耗、高对比度和快速响应等优点。 根据接线方式的不同,OLED显示屏可以分为四针和七针两种。
一、四针OLED显示屏
1. 接线方式:四针OLED显示屏通常由VCC、GND、SDA和SCL四个引脚组成,其中VCC和GND用于供电,SDA和SCL用于数据传输。
2. 特点:四针OLED显示屏通常采用I2C通信协议,具有简单的接线方式和易于控制的特点。
3. 优势:I2C通信协议不需要额外的引脚来传输数据,能够降低设备的成本和复杂度。
4. 应用领域:四针OLED显示屏适用于小型电子设备中,如智能手表、手持设备等。
二、七针OLED显示屏
1. 接线方式:七针OLED显示屏通常由VCC、GND、SCK、SDA、RES、DC和CS七个引脚组成,其中SCK和SDA用于数据传输,RES用于复位,DC用于数据/命令选择,CS用于片选。
2. 特点:七针OLED显示屏通常采用SPI通信协议,具有高速传输和更丰富的功能选择。
3. 优势:SPI通信协议能够实现高速数据传输,适合在需要快速响应的设备中使用。
4. 应用领域:七针OLED显示屏适用于大型电子设备中,如工业控制、汽车显示屏等。
根据不同的接线方式,四针和七针OLED显示屏在应用场景和特点上有所区别,用户可以根据具体需求选择合适的显示屏类型以实现更好的显示效果和控制体验。
蜂鸣器模块。
代码:
首先贴出代码部分:
oled.c
#include "stm32f10x.h"
#include "OLED_Font.h"
#include "stdio.h"
/* OLED_ShowChar(1, 1, 'A');
OLED_ShowString(1, 3, "HelloWorld!");
OLED_ShowNum(2, 1, 12345, 5);
OLED_ShowSignedNum(2, 7, -66, 2);
OLED_ShowHexNum(3, 1, 0xAA55, 4);
OLED_ShowBinNum(4, 1, 0xAA55, 16);
OLED_ShowFNum(1, 1 , Fnum); */
/*引脚配置*/
#define OLED_W_SCL(x) GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
#define OLED_W_SDA(x) GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))
/*引脚初始化*/
void OLED_I2C_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Init(GPIOB, &GPIO_InitStructure);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
/**
* @brief I2C开始
* @param 无
* @retval 无
*/
void OLED_I2C_Start(void)
{
OLED_W_SDA(1);
OLED_W_SCL(1);
OLED_W_SDA(0);
OLED_W_SCL(0);
}
/**
* @brief I2C停止
* @param 无
* @retval 无
*/
void OLED_I2C_Stop(void)
{
OLED_W_SDA(0);
OLED_W_SCL(1);
OLED_W_SDA(1);
}
/**
* @brief I2C发送一个字节
* @param Byte 要发送的一个字节
* @retval 无
*/
void OLED_I2C_SendByte(uint8_t Byte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
OLED_W_SDA(Byte & (0x80 >> i));
OLED_W_SCL(1);
OLED_W_SCL(0);
}
OLED_W_SCL(1); //额外的一个时钟,不处理应答信号
OLED_W_SCL(0);
}
/**
* @brief OLED写命令
* @param Command 要写入的命令
* @retval 无
*/
void OLED_WriteCommand(uint8_t Command)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x00); //写命令
OLED_I2C_SendByte(Command);
OLED_I2C_Stop();
}
/**
* @brief OLED写数据
* @param Data 要写入的数据
* @retval 无
*/
void OLED_WriteData(uint8_t Data)
{
OLED_I2C_Start();
OLED_I2C_SendByte(0x78); //从机地址
OLED_I2C_SendByte(0x40); //写数据
OLED_I2C_SendByte(Data);
OLED_I2C_Stop();
}
/**
* @brief OLED设置光标位置
* @param Y 以左上角为原点,向下方向的坐标,范围:0~7
* @param X 以左上角为原点,向右方向的坐标,范围:0~127
* @retval 无
*/
void OLED_SetCursor(uint8_t Y, uint8_t X)
{
OLED_WriteCommand(0xB0 | Y); //设置Y位置
OLED_WriteCommand(0x10 | ((X & 0xF0) >> 4)); //设置X位置高4位
OLED_WriteCommand(0x00 | (X & 0x0F)); //设置X位置低4位
}
/**
* @brief OLED清屏
* @param 无
* @retval 无
*/
void OLED_Clear(void)
{
uint8_t i, j;
for (j = 0; j < 8; j++)
{
OLED_SetCursor(j, 0);
for(i = 0; i < 128; i++)
{
OLED_WriteData(0x00);
}
}
}
/**
* @brief OLED显示一个字符
* @param Line 行位置,范围:1~4
* @param Column 列位置,范围:1~16
* @param Char 要显示的一个字符,范围:ASCII可见字符
* @retval 无
*/
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char)
{
uint8_t i;
OLED_SetCursor((Line - 1) * 2, (Column - 1) * 8); //设置光标位置在上半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i]); //显示上半部分内容
}
OLED_SetCursor((Line - 1) * 2 + 1, (Column - 1) * 8); //设置光标位置在下半部分
for (i = 0; i < 8; i++)
{
OLED_WriteData(OLED_F8x16[Char - ' '][i + 8]); //显示下半部分内容
}
}
/**
* @brief OLED显示字符串
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串,范围:ASCII可见字符
* @retval 无
*/
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String)
{
uint8_t i;
for (i = 0; String[i] != '\0'; i++)
{
OLED_ShowChar(Line, Column + i, String[i]);
}
}
/**
* @brief OLED次方函数
* @retval 返回值等于X的Y次方
*/
uint32_t OLED_Pow(uint32_t X, uint32_t Y)
{
uint32_t Result = 1;
while (Y--)
{
Result *= X;
}
return Result;
}
/**
* @brief OLED显示数字(十进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~4294967295
* @param Length 要显示数字的长度,范围:1~10
* @retval 无
*/
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
* @brief OLED显示数字(十进制,带符号数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-2147483648~2147483647
* @param Length 要显示数字的长度,范围:1~10
* @retval 无
*/
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length)
{
uint8_t i;
uint32_t Number1;
if (Number >= 0)
{
OLED_ShowChar(Line, Column, '+');
Number1 = Number;
}
else
{
OLED_ShowChar(Line, Column, '-');
Number1 = -Number;
}
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i + 1, Number1 / OLED_Pow(10, Length - i - 1) % 10 + '0');
}
}
/**
* @brief OLED显示数字(十六进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFFFFFF
* @param Length 要显示数字的长度,范围:1~8
* @retval 无
*/
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i, SingleNumber;
for (i = 0; i < Length; i++)
{
SingleNumber = Number / OLED_Pow(16, Length - i - 1) % 16;
if (SingleNumber < 10)
{
OLED_ShowChar(Line, Column + i, SingleNumber + '0');
}
else
{
OLED_ShowChar(Line, Column + i, SingleNumber - 10 + 'A');
}
}
}
/**
* @brief OLED显示数字(二进制,正数)
* @param Line 起始行位置,范围:1~4
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length)
{
uint8_t i;
for (i = 0; i < Length; i++)
{
OLED_ShowChar(Line, Column + i, Number / OLED_Pow(2, Length - i - 1) % 2 + '0');
}
}
/****************************************************************
* void OLED_ShowFNum() 显示任意浮点数,参考中景园OLED_ShowNum()函数
* x , y : 起点坐标
* Fnum : 要显示的浮点数
* size1 : 字体大小
* mode : 0,反色显示;1,正常显示
* @作 者 : Guard_Byte
***************************************************************/
void OLED_ShowFNum(u8 x,u8 y,float Fnum,u8 size1)
{
char Data[]= " "; //创建目标数组,用来存放转换后的字符数据
sprintf(Data,"%.3f",Fnum); //保留小数点后3位小数,打印到Data数组中 //判断浮点数长度,方便后期打印输出
OLED_ShowString(x,y,Data); //调用OLED字符串显示函数,在OLED屏上显示
}
/**
* @brief OLED初始化
* @param 无
* @retval 无
*/
void OLED_Init(void)
{
uint32_t i, j;
for (i = 0; i < 1000; i++) //上电延时
{
for (j = 0; j < 1000; j++);
}
OLED_I2C_Init(); //端口初始化
OLED_WriteCommand(0xAE); //关闭显示
OLED_WriteCommand(0xD5); //设置显示时钟分频比/振荡器频率
OLED_WriteCommand(0x80);
OLED_WriteCommand(0xA8); //设置多路复用率
OLED_WriteCommand(0x3F);
OLED_WriteCommand(0xD3); //设置显示偏移
OLED_WriteCommand(0x00);
OLED_WriteCommand(0x40); //设置显示开始行
OLED_WriteCommand(0xA1); //设置左右方向,0xA1正常 0xA0左右反置
OLED_WriteCommand(0xC8); //设置上下方向,0xC8正常 0xC0上下反置
OLED_WriteCommand(0xDA); //设置COM引脚硬件配置
OLED_WriteCommand(0x12);
OLED_WriteCommand(0x81); //设置对比度控制
OLED_WriteCommand(0xCF);
OLED_WriteCommand(0xD9); //设置预充电周期
OLED_WriteCommand(0xF1);
OLED_WriteCommand(0xDB); //设置VCOMH取消选择级别
OLED_WriteCommand(0x30);
OLED_WriteCommand(0xA4); //设置整个显示打开/关闭
OLED_WriteCommand(0xA6); //设置正常/倒转显示
OLED_WriteCommand(0x8D); //设置充电泵
OLED_WriteCommand(0x14);
OLED_WriteCommand(0xAF); //开启显示
OLED_Clear(); //OLED清屏
}
oled.h
#ifndef __OLED_H
#define __OLED_H
void OLED_Init(void);
void OLED_Clear(void);
void OLED_ShowChar(uint8_t Line, uint8_t Column, char Char);
void OLED_ShowString(uint8_t Line, uint8_t Column, char *String);
void OLED_ShowNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowSignedNum(uint8_t Line, uint8_t Column, int32_t Number, uint8_t Length);
void OLED_ShowHexNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowBinNum(uint8_t Line, uint8_t Column, uint32_t Number, uint8_t Length);
void OLED_ShowFNum(u8 x,u8 y,float Fnum);
int Pow(int X, int Y);
int xiao_shu(uint8_t Line, uint8_t Column,float Number1,int Length);
#endif
dist.c
#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "dist.h"
#include "delay.h"
void TIM4_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
// NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//使能TIM4时钟
TIM_TimeBaseInitStructure.TIM_Prescaler = 0;
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period = 0xffff;
TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);
TIM_PrescalerConfig(TIM4,71, TIM_PSCReloadMode_Immediate);
TIM_ARRPreloadConfig(TIM4,DISABLE);
TIM_SetCounter(TIM4,0); //TIM4计数值清零
TIM_Cmd(TIM4,DISABLE); //TIM4计数器失能
}
int GetDistance(void)
{
// dist_INIT();
int dis;
int count;
GPIO_ResetBits(dist_Echo_PORT,dist_Echo_PIN); //echo端口复位
GPIO_ResetBits(dist_Trig_PORT,dist_Trig_Pin); //trig端口复位
TIM_SetCounter(TIM4,0); //TIM4计数值清零
GPIO_SetBits(dist_Trig_PORT,dist_Trig_Pin); //trig置高 发出10us的高电平信号
Delay_us(10);
GPIO_ResetBits(dist_Trig_PORT,dist_Trig_Pin);
Delay_us(100);
while(GPIO_ReadInputDataBit(dist_Echo_PORT, dist_Echo_PIN) == 0);
TIM_Cmd(TIM4,ENABLE); //开启计数器
//开启定时器开始计时
while(GPIO_ReadInputDataBit(dist_Echo_PORT, dist_Echo_PIN)); //等待echo置低
TIM_Cmd(TIM4,DISABLE); //关闭计数器
count = TIM_GetCounter(TIM4);//获取计数器值
dis = (int)count/60.034;//转换为距离,即29.034us超声波能传播1cm
Delay_ms(100);
return dis;
}
//在dist.c中对引脚进行初始化
//对超声波传感器的端口进行初始化
void dist_INIT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;//定义结构体变量
RCC_APB2PeriphClockCmd(dist_Echo_RCC|dist_Trig_RCC,ENABLE);//开启时钟
GPIO_InitStructure.GPIO_Pin=dist_Echo_PIN; //选择你要设置的IO口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //设置浮空输入
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率
GPIO_Init(dist_Echo_PORT,&GPIO_InitStructure); /* 初始化GPIO */
GPIO_InitStructure.GPIO_Pin=dist_Trig_Pin; //选择你要设置的IO口
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //设置推挽输出
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //设置传输速率
GPIO_Init(dist_Trig_PORT,&GPIO_InitStructure); /* 初始化GPIO */
}
dist.h
#ifndef __DIST_H
#define __DIST_H
#define dist_Echo_PORT GPIOB
#define dist_Trig_PORT GPIOB
#define dist_Echo_PIN GPIO_Pin_10
#define dist_Trig_Pin GPIO_Pin_11
#define dist_Echo_RCC RCC_APB2Periph_GPIOB
#define dist_Trig_RCC RCC_APB2Periph_GPIOB
#include "stm32f10x.h"
void dist_INIT(void);
void TIM4_Init(void);
int GetDistance(void);
#endif
max6675.c
#include "MAX6675.h"
// unsigned int t,i;
// unsigned char c;
// unsigned char flag;
// float temprature;
/*
* 函数名:SPI1_Init
* 描述 MAX6675 接口初始化
* 输入 :无
* 输出 :无
* 返回 :无
*/
void SPI_MAX6675_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
/* 使能 SPI1 时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_SPI1, ENABLE);
/* ---------通信I/O初始化----------------
* PA5-SPI1-SCK :MAX6675_SCK
* PA6-SPI1-MISO:MAX6675_SO
* PA7-SPI1-MOSI:MAX6675_SI 在这里暂时不用
*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* ---------控制I/O初始化----------------*/
/* PA4-SPI1-NSS:MAX6675_CS */ // 片选
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推免输出
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_SetBits(GPIOA, GPIO_Pin_4); // 先把片选拉高,真正用的时候再拉低
/* SPI1 配置 */
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
/* 使能 SPI1 */
SPI_Cmd(SPI1, ENABLE);
}
/*
*
*
*
*/
unsigned char MAX6675_ReadByte(void)
{
/* Loop while DR register in not emplty */
while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET);
/* Send byte through the SPI1 peripheral */
SPI_I2S_SendData(SPI1, 0xff);
/* Wait to receive a byte */
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET);
/* Return the byte read from the SPI bus */
return SPI_I2S_ReceiveData(SPI1);
}
//void GetTemprture( unsigned int t,unsigned int i,unsigned char c,unsigned char flag,float temprature)
//{
//
// MAX6675_CSL();
// c = MAX6675_ReadByte();
// i = c;
// i = i<<8;
// c = MAX6675_ReadByte();
// MAX6675_CSH();
//
// i = i|((unsigned int)c); //i是读出来的原始数据
// flag = i&0x04; //flag保存了热电偶的连接状态
// t = i<<1;
// t = t>>4;
// temprature = t*0.25; //这里就是获取温度
//
//}
max6675.h
#ifndef __MAX6675_H
#define __MAX6675_H
#include "stm32f10x.h"
#define MAX6675_CS GPIO_Pin_4
#define MAX6675_CSL() GPIOA->BRR = MAX6675_CS;
#define MAX6675_CSH() GPIOA->BSRR = MAX6675_CS;
void SPI_MAX6675_Init(void);
unsigned char MAX6675_ReadByte(void);
//void GetTemprture( unsigned int t,unsigned int i,unsigned char c,unsigned char flag,float temprature);
#endif
beep.c
里面不完全是Beep的初始化,因为LED调试灯显示与继电器开关也是操作GPIO口,所以这里对这些也进行了初始化!
#include "BEEP.h"
void fire_Init(void)
{ GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_ResetBits(GPIOA, GPIO_Pin_8);
}
void BEEP_Init(void)
{ GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_SetBits(GPIOC, GPIO_Pin_13);
}
void BEEF_Init(void)
{ GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
}
beep.h
#ifndef __BEEP_H
#define __BEEP_H
#include "stm32f10x.h"
void BEEP_Init(void);
void BEEF_Init(void);
void fire_Init(void);
#endif
AD.c
该部分代码主要是MQ-2的ADC采集部分
#include "AD.h" // Device header
#include "Delay.h"
void AD_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_NbrOfChannel = 1;
ADC_Init(ADC1, &ADC_InitStructure);
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1) == SET);
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);
}
uint16_t AD_GetValue(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
return ADC_GetConversionValue(ADC1);
}
//多次取值,求平均值提高准确性
u16 get_gas_average(u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++) //times=10
{
temp_val+= AD_GetValue();
Delay_ms(5);
}
return temp_val/times;//返回ADC采集的数据的平均值
}
void get_gas_real_value(float* value)
{
u16 gas_val=0;
gas_val = get_gas_average(10);//得到ADC通道获取的平均值
*value = (gas_val/4095.0*3.3)*210+ 10;//燃气值计算公式可以查看MQ-5数据手册
}
AD.h
#ifndef __AD_H
#define __AD_H
#include "stm32f10x.h" // Device header
void AD_Init(void);
uint16_t AD_GetValue(void);
u16 get_gas_average(u8 times);
void get_gas_real_value(float* value);
#endif
检测错误判断
分别是温度超过阈值,天然气浓度超过阈值,与距离超过阈值!
对应阈值定义:
void ERROR_alarm() //错误显示
{
if(state_flag == 1)
{
OLED_ShowString(1 ,1 ,"Over temperature");
if(state_pre_flag!=state_flag)
OLED_Clear();
}
if(state_flag == 2)
{
OLED_ShowString(1 ,1 ,"Over distance");
if(state_pre_flag!=state_flag)
OLED_Clear();
}
if(state_flag == 3)
{
OLED_ShowString(1 ,1 ,"Over CO/CH4");
if(state_pre_flag!=state_flag)
OLED_Clear();
}
}
void ERROR_judgement() //错误判断+操作
{
if(temprature >= a )
{
state_flag =1;
GPIO_SetBits(GPIOC, GPIO_Pin_13); //风扇
GPIO_SetBits(GPIOA, GPIO_Pin_8);
GPIO_SetBits(GPIOB, GPIO_Pin_0);
}
else if(dist >= b2 )
{
state_flag =2;
GPIO_SetBits(GPIOC, GPIO_Pin_13); //风扇
GPIO_SetBits(GPIOA, GPIO_Pin_8);
GPIO_SetBits(GPIOB, GPIO_Pin_0);
}
else if( value >= r)
{
state_flag =3;
GPIO_SetBits(GPIOC, GPIO_Pin_13); //风扇
GPIO_SetBits(GPIOB, GPIO_Pin_8);
}
else{
GPIO_ResetBits(GPIOC, GPIO_Pin_13); //蜂鸣器
GPIO_ResetBits(GPIOB, GPIO_Pin_0); //风扇
GPIO_ResetBits(GPIOA, GPIO_Pin_8);
state_flag =0;
}
}
main.c
int main(void)
{
OLED_Init();
AD_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
dist_INIT();
TIM4_Init();
SPI_MAX6675_Init();//MAX6675 SPI 接口初始化
BEEP_Init();
BEEF_Init();
fire_Init();
while (1)
{
dist=GetDistance(); //获取距离
Delay_ms(50);
/***************************/
MAX6675_CSL();
c = MAX6675_ReadByte();
i = c;
i = i<<8;
c = MAX6675_ReadByte();
MAX6675_CSH();
i = i|((unsigned int)c); //i是读出来的原始数据
t = i<<1;
t = t>>4;
temprature = t*0.25; //这里就是获取温度
/***************************/
if(state_flag == 0) //正常显示
{
OLED_ShowString(1 ,1,"TMP: ");
OLED_ShowFNum(1, 5 , temprature);
OLED_ShowString(3,12,"'C");
OLED_ShowString(2 ,1 ,"DIS: ");
OLED_ShowSignedNum(2, 5 , dist,3);
OLED_ShowString(3,12,"cm");
get_gas_real_value(&value);
OLED_ShowString(3,1,"RQ: ");
OLED_ShowFNum(3, 4 , value);
OLED_ShowString(3,12,"ppm");
if(state_pre_flag!=state_flag)
OLED_Clear();
}
ERROR_judgement(); //错误判断+操作
ERROR_alarm(); //错误显示
state_pre_flag = state_flag;
}
}
在这里,OLED屏幕会一直刷新影响我们观看体验,所以我们采用有数据来才刷新的方式,定义了state_pre_flag以及state_flag这两个变量,只有两者不同标志着数据已经发生改变,则需要清屏幕刷新操作!
焊接调试
测试视频:
厨房检测系统测试视频
代码:
https://download.csdn.net/download/qq_62316532/89373544?spm=1001.2014.3001.5501