一,灵感来源
在淘宝上看到有卖翻转定时的闹钟,于是灵感来了想用stm32来写一个相同的程序,实物如图:
二,所需硬件
stm32单片机,st-link下载器,MPU6050姿态传感器,0.96寸OLED显示屏,按键,LED(用来代替蜂鸣器,定时时间到了的标志)。
三,效果演示
四,代码部分
主要思路:采用状态机,分成三种状态:初始化,设置需要定时的时间,开始计时。用姿态传感器的x,y的数据的正负来实现选择要定时的时间,用定时器每一秒进行一次中断,每中断一次sec减1,每减60次Time减一,直至Time和sec都为0,计时结束。
1,参考了江科大的代码,采用状态机来进行每步操作
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"
#include "Timer.h"
#include "Key.h"
#include "LED.h"
#define Reset 0 //初始化的状态
#define START 1 //开始计时的状态
#define SETNUM 2 //设置时间的状态
2,状态机部分
uint8_t state=0,KeyNum;
int16_t AX,AY,AZ,GX,GY,GZ;
uint8_t Sec=0,Time;
void stateMachine(void)
{
if(state==Reset)
{
LED_Init();
OLED_Init();
MPU6050_Init();
Key_Init();
Timer_Init();
state=SETNUM; //切换下一个状态
}
if(state==SETNUM) //陀螺仪传感器设定时间的代码
{
if(AX>=500)
{
Time=1;
}
if(AX<=-500)
{
Time=15;
}
if(AY>=500)
{
Time=5;
}
if(AY<=-500)
{
Time=30;
}
KeyNum=Key_GetNum();
if(KeyNum==1) //如果按键被按下时切换为开始计时的状态
{
state=START;
}
}
if(state==START)
{
TIM_Cmd(TIM2,ENABLE); //定时器使能
if(Time==0&&Sec==0)
{
TIM_Cmd(TIM2,DISABLE); //定时器使能
LED2_ON();
OLED_ShowString(2,1,"Time up!");
}
}
}
3,主函数部分
int main(void)
{
while(1)
{
MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);
stateMachine();
OLED_ShowNum(1,1,Time,2);
OLED_ShowString(1,3,":");
OLED_ShowNum(1,4,Sec,2);
}
}
4,中断函数部分
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
Sec--;
if(Sec>61)
{
Sec=60;
Time--;
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
5,其他模块的函数
//定时器中断函数
extern uint16_t Num;
void Timer_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStructure.TIM_Period=10000-1 ;//arr自动重载器的值
TIM_TimeBaseInitStructure.TIM_Prescaler=7200-1;//psc预分频器的值
TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;//重复计数器
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
TIM_ClearFlag(TIM2,TIM_FLAG_Update);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1 ;
NVIC_Init(&NVIC_InitStructure);
}
//MPU6050函数部分
#define MPU6050_ADDRESS 0xD0
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
MyI2C_Start();
MyI2C_SendByte(MPU6050_ADDRESS);
MyI2C_ReceiveAck();
MyI2C_SendByte(RegAddress);
MyI2C_ReceiveAck();
MyI2C_SendByte(Data);
MyI2C_ReceiveAck();
MyI2C_Stop();
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress,uint8_t Fre)
{
uint8_t Data,i;
MyI2C_Start();
MyI2C_SendByte(MPU6050_ADDRESS);
MyI2C_ReceiveAck();
MyI2C_SendByte(RegAddress);
MyI2C_ReceiveAck();
MyI2C_Start();
MyI2C_SendByte(MPU6050_ADDRESS|0x01);
MyI2C_ReceiveAck();
for(i=0;i<(Fre-1);i++)
{
Data=MyI2C_ReceiveByte();
MyI2C_SendAck(0);
}
Data=MyI2C_ReceiveByte();
MyI2C_SendAck(1);
MyI2C_Stop();
return Data;
}
void MPU6050_Init(void)
{
MyI2C_Init();
MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);
MPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);
MPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);
MPU6050_WriteReg(MPU6050_CONFIG,0x06);
MPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);
MPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);
}
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,
int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ)
{
uint8_t DataH,DataL;
DataH=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H,1);
DataL=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L,1);
*AccX=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H,1);
DataL=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L,1);
*AccY=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H,1);
DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L,1);
*AccZ=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_GYRO_XOUT_H,1);
DataL=MPU6050_ReadReg(MPU6050_GYRO_XOUT_L,1);
*GyroX=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_GYRO_YOUT_H,1);
DataL=MPU6050_ReadReg(MPU6050_GYRO_YOUT_L,1);
*GyroY=(DataH<<8)|DataL;
DataH=MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H,1);
DataL=MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L,1);
*GyroZ=(DataH<<8)|DataL;
}