原理
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); //标志位清零
}
原理
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); //标志位清零
}
举报