STM32
直播中

石玉兰

7年用户 1417经验值
私信 关注
[问答]

怎么实现温度检测仪器的设计?

怎么实现温度检测仪器的设计?

回帖(1)

孔喆

2021-11-18 15:16:31
原理

STM32ADC采样,我选用PA5作为ADC接口,并做了UI设计。






KEY配置
key.c


#include "key.h"
#include "SysTick.h"




//按键初始化函数
void KEY_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOA,ENABLE); //使能端口时钟
       
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; //输入模式
        GPIO_InitStructure.GPIO_Pin=KEY_LEFT_Pin|KEY_DOWN_Pin|KEY_RIGHT_Pin;//管脚设置
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;//上拉
        GPIO_Init(KEY_Port,&GPIO_InitStructure); //初始化结构体
       
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; //输入模式
        GPIO_InitStructure.GPIO_Pin=KEY_UP_Pin;//管脚设置
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;//下拉
        GPIO_Init(KEY_UP_Port,&GPIO_InitStructure); //初始化结构体
}


//mode=0:单次按下按键
//mode=1:连续按下按键
//返回值:0表示未有按键按下
u8 KEY_Scan(u8 mode)
{
        static u8 key=1;
        if(key==1&&(K_UP==1||K_DOWN==0||K_LEFT==0||K_RIGHT==0)) //任意一个按键按下
        {
                delay_ms(10);  //消抖
                key=0;
                if(K_UP==1)
                {
                        return KEY_UP;
                }
                else if(K_DOWN==0)
                {
                        return KEY_DOWN;
                }
                else if(K_LEFT==0)
                {
                        return KEY_LEFT;
                }
                else
                {
                        return KEY_RIGHT;
                }
        }
        else if(K_UP==0&&K_DOWN==1&&K_LEFT==1&&K_RIGHT==1)    //无按键按下
        {
                key=1;
        }
        if(mode==1) //连续按键按下
        {
                key=1;
        }
        return 0;
}




key.h


#ifndef _key_H
#define _key_H




#include "system.h"

#define KEY_LEFT_Pin    GPIO_Pin_4    //定义K_LEFT管脚
#define KEY_DOWN_Pin    GPIO_Pin_3    //定义K_DOWN管脚
#define KEY_RIGHT_Pin   GPIO_Pin_2   //定义K_RIGHT管脚
#define KEY_UP_Pin      GPIO_Pin_0  //定义KEY_UP管脚


#define KEY_Port (GPIOE) //定义端口
#define KEY_UP_Port (GPIOA) //定义端口




//使用位操作定义
#define K_UP PAin(0)
#define K_DOWN PEin(3)
#define K_LEFT PEin(4)
#define K_RIGHT PEin(2)


//使用读取管脚状态库函数定义
//#define K_UP      GPIO_ReadInputDataBit(KEY_UP_Port,KEY_UP_Pin)
//#define K_DOWN    GPIO_ReadInputDataBit(KEY_Port,KEY_DOWN_Pin)
//#define K_LEFT    GPIO_ReadInputDataBit(KEY_Port,KEY_LEFT_Pin)
//#define K_RIGHT   GPIO_ReadInputDataBit(KEY_Port,KEY_RIGHT_Pin)




//定义各个按键值  
#define KEY_UP 1
#define KEY_DOWN 2
#define KEY_LEFT 3
#define KEY_RIGHT 4  






void KEY_Init(void);
u8 KEY_Scan(u8 mode);
#endif


ADC配置
adc.h


#ifndef _adc_H
#define _adc_H


#include "system.h"


void ADCx_Init(void);
u16 Get_ADC_Value(u8 ch,u8 times);


int Get_temp(void);
#endif


adc.c


#include "adc.h"
#include "SysTick.h"




//初始化ADC       
void ADCx_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量       
        ADC_CommonInitTypeDef ADC_CommonInitStructure;
        ADC_InitTypeDef       ADC_InitStructure;
       
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
       
       
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AN; //模拟输入模式
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;//管脚设置
        GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;//浮空
        GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化结构体
       
        //RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);          //ADC1复位
        //RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);        //复位结束
       
        ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
        ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟
        ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能
        ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz
        ADC_CommonInit(&ADC_CommonInitStructure);//初始化
       
        ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
        ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式       
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
        ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐       
        ADC_InitStructure.ADC_NbrOfConversion = 1;//1个转换在规则序列中 也就是只转换规则序列1
        ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化
       
        ADC_Cmd(ADC1, ENABLE);//开启AD转换器
}




//获取通道ch的转换值,取times次,然后平均
//ch:通道编号
//times:获取次数
//返回值:通道ch的times次转换结果平均值
u16 Get_ADC_Value(u8 ch,u8 times)
{
        u32 temp_val=0;
        u8 t;
        //设置指定ADC的规则组通道,一个序列,采样时间
        ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_480Cycles);        //ADC1,ADC通道,480个周期,提高采样时间可以提高精确度                            
       
        for(t=0;t         {
                ADC_SoftwareStartConv(ADC1);                //使能指定的ADC1的软件转换启动功能       
                while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
                temp_val+=ADC_GetConversionValue(ADC1);
                delay_ms(5);
        }
        return temp_val/times;
}
//得到温度值
//返回值:温度值(扩大了100倍,单位:℃.)
int Get_temp(void)
{
        u32 adc_value;
        int temp;
        double temperture;
        adc_value=Get_ADC_Value(ADC_Channel_5,20);        //读取通道16内部温度传感器通道,10次取平均
        temperture=(float)adc_value*(3.3/4096);                //电压值
        temperture=(temperture-0.38)/0.0025; //转换为温度值 + 25
        temp=temperture*10;                                        //扩大100倍.
        return temp;
}


中断配置
定时器配置


#include "time.h"
#include "led.h"
#include "adc_temp.h"
//per:重装载值
//psc:分频系数
extern u8 tempture_t;
void TIM4_Init(u16 per,u16 psc)
{
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);//使能TIM4时钟
       
        TIM_TimeBaseInitStructure.TIM_Period=per;   //自动装载值
        TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //分频系数
        TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
        TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //设置向上计数模式
        TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitStructure);
       
        TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); //开启定时器中断
        TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
       
        NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;//定时器中断通道
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;                //子优先级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);       
       
        TIM_Cmd(TIM4,ENABLE); //使能定时器       
}


中断服务函数


void TIM4_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM4,TIM_IT_Update))
        {
                led2=!led2;
                tempture.temp=Get_temp();//读ADC值
                TIM4->ARR= tempture.Sampling_period-1;//读取周期可控制
        }
        TIM_ClearITPendingBit(TIM4,TIM_IT_Update);        //标志位清零
}


UI及主函数
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "tftlcd.h"
#include "key.h"
#include "mpu6050.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
//#include "adc_temp.h"
#include "adc.h"
#include "time.h"
u8 key;//按键
struct test
{
    short temp;
    float temp_want;
                int mode;
    int Sampling_period;
                int u_limit;
                int l_limit;
};
struct statue_menu
{
    int temp_want;
                int temp_want_change;
    int Sampling_period;
                int Sampling_period_change;
                int key_switch;
                int u_limit;
                int l_limit;
};
struct test tempture;//温度示数
struct statue_menu statue_menu_t;//显示示数 防止超限影响显示


//串口1发送1个字符
//c:要发送的字符
void usart1_send_char(u8 c)
{
        while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
    USART_SendData(USART1,c);   


}


//传送数据给匿名四轴上位机软件(V2.6版本)
//fun:功能字. 0XA0~0XAF
//data:数据缓存区,最多28字节!!
//len:data区有效数据个数
void usart1_niming_report(u8 fun,u8*data,u8 len)
{
        u8 send_buf[32];
        u8 i;
        if(len>28)return;        //最多28字节数据
        send_buf[len+3]=0;        //校验数置零
        send_buf[0]=0X88;        //帧头
        send_buf[1]=fun;        //功能字
        send_buf[2]=len;        //数据长度
        for(i=0;i;                        //复制数据
        for(i=0;i;        //计算校验和       
        for(i=0;i);        //发送数据到串口1
}


//发送加速度传感器数据和陀螺仪数据
//aacx,aacy,aacz:x,y,z三个方向上面的加速度值
//gyrox,gyroy,gyroz:x,y,z三个方向上面的陀螺仪值
void mpu6050_send_data(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz)
{
        u8 tbuf[12];
        tbuf[0]=(aacx>>8)&0XFF;
        tbuf[1]=aacx&0XFF;
        tbuf[2]=(aacy>>8)&0XFF;
        tbuf[3]=aacy&0XFF;
        tbuf[4]=(aacz>>8)&0XFF;
        tbuf[5]=aacz&0XFF;
        tbuf[6]=(gyrox>>8)&0XFF;
        tbuf[7]=gyrox&0XFF;
        tbuf[8]=(gyroy>>8)&0XFF;
        tbuf[9]=gyroy&0XFF;
        tbuf[10]=(gyroz>>8)&0XFF;
        tbuf[11]=gyroz&0XFF;
        usart1_niming_report(0XA1,tbuf,12);//自定义帧,0XA1
}       


//通过串口1上报结算后的姿态数据给电脑
//aacx,aacy,aacz:x,y,z三个方向上面的加速度值
//gyrox,gyroy,gyroz:x,y,z三个方向上面的陀螺仪值
//roll:横滚角.单位0.01度。 -18000 -> 18000 对应 -180.00  ->  180.00度
//pitch:俯仰角.单位 0.01度。-9000 - 9000 对应 -90.00 -> 90.00 度
//yaw:航向角.单位为0.1度 0 -> 3600  对应 0 -> 360.0度
void usart1_report_imu(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz,short roll,short pitch,short yaw)
{
        u8 tbuf[28];
        u8 i;
        for(i=0;i<28;i++)tbuf=0;//清0
        tbuf[0]=(aacx>>8)&0XFF;
        tbuf[1]=aacx&0XFF;
        tbuf[2]=(aacy>>8)&0XFF;
        tbuf[3]=aacy&0XFF;
        tbuf[4]=(aacz>>8)&0XFF;
        tbuf[5]=aacz&0XFF;
        tbuf[6]=(gyrox>>8)&0XFF;
        tbuf[7]=gyrox&0XFF;
        tbuf[8]=(gyroy>>8)&0XFF;
        tbuf[9]=gyroy&0XFF;
        tbuf[10]=(gyroz>>8)&0XFF;
        tbuf[11]=gyroz&0XFF;       
        tbuf[18]=(roll>>8)&0XFF;
        tbuf[19]=roll&0XFF;
        tbuf[20]=(pitch>>8)&0XFF;
        tbuf[21]=pitch&0XFF;
        tbuf[22]=(yaw>>8)&0XFF;
        tbuf[23]=yaw&0XFF;
        usart1_niming_report(0XAF,tbuf,28);//飞控显示帧,0XAF
}










void menu_display()
{
       
                if(key==KEY_UP)
                {
                        statue_menu_t.key_switch--;//选项指示标志位


                }
                if(key==KEY_DOWN)
                {
                        statue_menu_t.key_switch++;


                }
                if(statue_menu_t.key_switch<0||statue_menu_t.key_switch>4)//超出范围清零
                        statue_menu_t.key_switch=0;
               
                if(statue_menu_t.key_switch==0)
                {
                       
                        LCD_ShowString(10+120,220,tftlcd_data.width,tftlcd_data.height,16,"<-");       
                        LCD_ShowString(10+120,260,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        LCD_ShowString(10+120,280,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        LCD_ShowString(10+120,300,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        if(key==KEY_RIGHT)
                        {
                                statue_menu_t.temp_want=statue_menu_t.temp_want+1;
                        }
                        if(key==KEY_LEFT)
                        {
                                statue_menu_t.temp_want=statue_menu_t.temp_want-1;
                        }
                }
               
                if(statue_menu_t.key_switch==1)
                {
               
                        LCD_ShowString(10+120,220,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        LCD_ShowString(10+120,260,tftlcd_data.width,tftlcd_data.height,16,"<-");
                        LCD_ShowString(10+120,280,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        LCD_ShowString(10+120,300,tftlcd_data.width,tftlcd_data.height,16,"  ");         
                       
                        if(key==KEY_RIGHT)
                        {
                                statue_menu_t.Sampling_period=statue_menu_t.Sampling_period+1000;
                        }
                        if(key==KEY_LEFT)
                        {
                                statue_menu_t.Sampling_period=statue_menu_t.Sampling_period-1000;
                        }
                        if(statue_menu_t.Sampling_period<500)
                        {statue_menu_t.Sampling_period=500;}
                        if(statue_menu_t.Sampling_period>=6000)
                        {statue_menu_t.Sampling_period=6000;}
                }
               
                if(statue_menu_t.key_switch==2)
                {
                        LCD_ShowString(10+120,220,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        LCD_ShowString(10+120,260,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        LCD_ShowString(10+120,280,tftlcd_data.width,tftlcd_data.height,16,"<-");
                        LCD_ShowString(10+120,300,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        if(key==KEY_RIGHT)
                        {
                                statue_menu_t.u_limit=statue_menu_t.u_limit+1;
                        }
                        if(key==KEY_LEFT)
                        {
                                statue_menu_t.u_limit=statue_menu_t.u_limit-1;
                        }
                }
               
                if(statue_menu_t.key_switch==3)
                {
                        LCD_ShowString(10+120,220,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        LCD_ShowString(10+120,260,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        LCD_ShowString(10+120,280,tftlcd_data.width,tftlcd_data.height,16,"  ");
                        LCD_ShowString(10+120,300,tftlcd_data.width,tftlcd_data.height,16,"<-");
                        if(key==KEY_RIGHT)
                        {
                                statue_menu_t.l_limit=statue_menu_t.l_limit+1;
                        }
                        if(key==KEY_LEFT)
                        {
                                statue_menu_t.l_limit=statue_menu_t.l_limit-1;
                        }
                }


        }




int main()
{       
        u8 i=0;
        //u8 key;
        u8 report=1;
        short temp;                                        //温度
        u8 res;
        SysTick_Init(168);
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组
        //
        LED_Init();//LED灯初始化
        USART1_Init(256000);//串口初始化
        TFTLCD_Init();                        //LCD初始化
        KEY_Init();                                        //按键初始化
        //ADC_Temp_Init();
        ADCx_Init();                                //ADC初始化
       
        TIM4_Init(5000-1,8400-1);  //定时500ms
       
        FRONT_COLOR=BLACK;//设置字体为黑色
        LCD_ShowString(10,10,tftlcd_data.width,tftlcd_data.height,16,"NJUST-ZJ STM32F4");
        LCD_ShowString(10,30,tftlcd_data.width,tftlcd_data.height,16,"170220228 LIU YIN FEI");
        LCD_ShowString(10,50,tftlcd_data.width,tftlcd_data.height,16,"TEMPTURE Test");
       
        FRONT_COLOR=RED;//设置字体为红色
        LCD_ShowString(10,130,tftlcd_data.width,tftlcd_data.height,16,"TEMPTURE OK!");
        //LCD_ShowString(10,150,tftlcd_data.width,tftlcd_data.height,16,"K_UP:UPLOAD ON/OFF");
        FRONT_COLOR=BLUE;//设置字体为蓝色
        LCD_ShowString(10,170,tftlcd_data.width,tftlcd_data.height,16,"UPLOAD ON ");         
        LCD_ShowString(10,200,tftlcd_data.width,tftlcd_data.height,16," Temp:    . C");       
        LCD_ShowString(10,220,tftlcd_data.width,tftlcd_data.height,16," Want:    . C");       
        LCD_ShowString(10,240,tftlcd_data.width,tftlcd_data.height,16," Mode:          ");         
        LCD_ShowString(10,260,tftlcd_data.width,tftlcd_data.height,16," period:     ms");       
        LCD_ShowString(10,280,tftlcd_data.width,tftlcd_data.height,16," U_limit:     C");
        LCD_ShowString(10,300,tftlcd_data.width,tftlcd_data.height,16," L_limit:     C");
        ///
        //赋初值
        tempture.temp_want=10.5;//期望温度赋值
        statue_menu_t.temp_want=10.5;
        tempture.Sampling_period=5000;//采样周期ms
        statue_menu_t.Sampling_period=5000;
        tempture.u_limit=50;
        tempture.l_limit=0;
        statue_menu_t.u_limit=50;
        statue_menu_t.l_limit=0;
       
        while(1)
        {
                key=KEY_Scan(0);//单次按下有效//按键模式选择
                menu_display();
                //tempture.temp=Get_temp();//ADC读取温度
                //显示参数处理
               
                tempture.mode=0;                                //加热或者降温
               
                //如果外界温度大于期望温度则降温
               
                if(tempture.temp_want>tempture.temp)
                        tempture.mode=0;
                else
                        tempture.mode=1;
                //数据同步
                tempture.u_limit=statue_menu_t.u_limit;
                tempture.l_limit=statue_menu_t.l_limit;
                tempture.temp_want=statue_menu_t.temp_want;
                tempture.Sampling_period=statue_menu_t.Sampling_period;
               
                tempture.temp_want=100*tempture.temp_want;
                //实时温度显示
                if(tempture.temp<0)
                {
                        LCD_ShowChar(10+48,200,'-',16,0);                //显示负号
                        tempture.temp=-tempture.temp;
                }
                else LCD_ShowChar(10+48,200,' ',16,0);                //去掉负号
               
                LCD_ShowNum(10+48+8,200,tempture.temp/100,3,16);                //显示整数部分            
                LCD_ShowNum(10+48+40,200,tempture.temp%10,1,16);                //显示小数部分
                //期望温度显示
               
                LCD_ShowNum(10+48+8,220,tempture.temp_want/100,3,16);                //显示整数部分            
                LCD_ShowNum(10+48+40,220,(int)tempture.temp_want/10,1,16);                //显示小数部分
                //模式显示
                if(tempture.mode==0)
                        LCD_ShowString(10,240,tftlcd_data.width,tftlcd_data.height,16," Mode:heating");
                if(tempture.mode==1)
                        LCD_ShowString(10,240,tftlcd_data.width,tftlcd_data.height,16," Mode:cooling");
                //采样周期显示
                LCD_ShowNum(10+48+14,260,tempture.Sampling_period,5,16);                //显示整数部分            
                //上限显示
                LCD_ShowNum(10+48+20,280,tempture.u_limit,3,16);                //显示整数部分
                //下限显示
                LCD_ShowNum(10+48+20,300,tempture.l_limit,3,16);                //显示整数部分
                //按键操作测试
                LCD_ShowNum(10,320,key,3,16);                //显示整数部分         
       
        }


}
//中断服务函数
void TIM4_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM4,TIM_IT_Update))
        {
                led2=!led2;
                tempture.temp=Get_temp();//读ADC值
                TIM4->ARR= tempture.Sampling_period-1;//读取周期可控制
        }
        TIM_ClearITPendingBit(TIM4,TIM_IT_Update);        //标志位清零
}
举报

更多回帖

×
20
完善资料,
赚取积分