STM32项目:重力感应的定时的闹钟

一,灵感来源

在淘宝上看到有卖翻转定时的闹钟,于是灵感来了想用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;

}

  • 9
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值