项目完成功能:
-
时间显示功能,能显示单片机中记录的时间。其时间可以用按键修改
-
整点报时功能,
-
根据重力调整时钟位置,整个时钟的会随着器件的转动而发生相应的改变。
因为数字是由字库显示的。所以数字和字符的朝向不能改变。
-
按键对应不同的功能:
-
调节时针
-
未定义
-
未定义
-
调节时针
-
所用板子资源介绍:
-
定时器3
-
LCD——软件模拟SPI协议
-
按键——外部中断
-
MPU6050——I2C协议
- 蜂鸣器——IO口模拟PWM输出
MPU6050
对于mpu6050,我们只要初始化IIC,按照手册进行收发命令,利用dmp进行姿态结算从而确定方向。
因为主函数里面的循环太多,如果卸载主函数里面mpu6050采集不到数据,所以把数据采集放在了定时器中断里面,同时又把重力调整时钟位置的函数写在这里,在数据采集的同时计算姿态,从而调整屏幕方向,因为定时器中断会一直执行,而有的函数执行多了会拖慢程序进程,所以在函数里面设置一个标志位,相同的运算就直接跳过,大大的节省了时间。
//回调函数,定时器中断服务函数调用
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==(&TIM3_Handler))
{
if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)
{
if(-100<yaw&&yaw<-60&&roll<170){mm=-180;o=1; ;}
if(-180<yaw&&yaw<-160&&pitch>10){mm=-180+90;o=2;}
if(90<yaw&&yaw<105&&roll<170){mm=-180+90*2;o=3;}
if(0<yaw&&yaw<30&&pitch<-10){mm=-180+90*3;o=4; }
if(n!=o){
LCD_DrawAngleLine2(120,120,180+90-s*360/(12*60*60),40,BLACK );
LCD_DrawAngleLine2(120,120,180-90-s*360/(12*60*60),8,BLACK );
LCD_DrawAngleLine2(120,120,180+90-s*360/(60*60),51,BLACK );
LCD_DrawAngleLine2(120,120,180-90-s*360/(60*60),12,BLACK );
s-=(o-1)*(3*60*60+15*60);
for(int j=12;mm<=180;mm+=6)
{
if(mm%30==0){
if(120+95*cos(mm*pi/180)<=120{
LCD_ShowIntNum(112+85*sin(mm*pi/180),112+85*cos(mm*pi/180),j,2,WHITE ,RED ,16);
j--;
if(j==0){
j=12;
}
}
else{
LCD_ShowIntNum(112+85*sin(mm*pi/180),
112+85*cos(mm*pi/180),j,2,WHITE ,RED,16);//
j--;
if(j==0){
j=12;
}
}
}
};
n=o;
}
}
}
}
蜂鸣器
一开始,直接给蜂鸣器接上高低电平,结果发现蜂鸣器只是短暂的响了一下,而且声音很低,需要离的很近才能听到,如果是有源蜂鸣器,内部会含有振荡源,所以这是无源蜂鸣器。
既然知道是什么问题了那就好办了,直接输出个PWMbo呗,结果一看数据手册发现该IO口没有定时器,没办法,只能模拟了呗,只需要输出4K~5K的方伯就可以驱动。
//引脚模拟PWM输出
void BEEP_OUT(int x){
int y=x*1000;
for(int i=0;i<y;i++){
PCout(10)=1;
delay_ms(100);
PCout(10)=0;
delay_ms(100);
}
}
后来下载尝试了一下,嗯,效果还不错哦。
按键
按键我们只要调整时间,要求也不是太高,将按键连接在外部中断上,然后调用中断函数,在中断函数里面就可以实现调整事件的功能啦。
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(50); //消抖
switch(GPIO_Pin)
{
case GPIO_PIN_9:
if(KEY_Scan(1)==1)
{
if(s<-10*60*60/2){
LCD_DrawAngleLine2(120,120,180+90-s*360/(12*60*60),40,BLACK );
LCD_DrawAngleLine2(120,120,180-90-s*360/(12*60*60),8,BLACK );
LCD_DrawAngleLine2(120,120,180+90-s*360/(60),66,BLACK );
LCD_DrawAngleLine2(120,120,180-90-s*360/(60),18,BLACK );
s=12*60*60/2;
break;
}
LCD_DrawAngleLine2(120,120,180+90-s*360/(12*60*60),40,BLACK );
LCD_DrawAngleLine2(120,120,180-90-s*360/(12*60*60),8,BLACK );
s-=60*60;
}
break;
/*
case GPIO_PIN_8:
if(KEY_Scan(1)==2)
{
}
break;
case GPIO_PIN_11:
if(KEY_Scan(1)==3)
{
}
break;
*/
case GPIO_PIN_12:
if(KEY_Scan(1)==4)
{
if(s<-12*58*60/2){
LCD_DrawAngleLine2(120,120,180+90-s*360/(12*60*60),40,BLACK );
LCD_DrawAngleLine2(120,120,180-90-s*360/(12*60*60),8,BLACK );
LCD_DrawAngleLine2(120,120,180+90-s*360/(60),66,BLACK );
LCD_DrawAngleLine2(120,120,180-90-s*360/(60),18,BLACK );
s=12*60*60/2;
break;
}
LCD_DrawAngleLine2(120,120,180+90-s*360/(12*60*60),40,BLACK );
LCD_DrawAngleLine2(120,120,180-90-s*360/(12*60*60),8,BLACK );
LCD_DrawAngleLine2(120,120,180+90-s*360/(60*60),52,BLACK );
LCD_DrawAngleLine2(120,120,180-90-s*360/(60*60),12,BLACK );
s-=2*60;
printf("\r\n%d\r\n",s);
}
break;
}
}
剩下的就简单许多了,只要在主函数里写个死循环,移植让秒针运动就OK啦。
while(1){
printf("\r\n*********\r\n");
for(;s>=-12*60*60/2;s--){
//时针
LCD_DrawAngleLine2(120,120,180+90-(s+1)*360/(12*60*60),40,BLACK );
LCD_DrawAngleLine2(120,120,180-90-(s+1)*360/(12*60*60),8,BLACK );
LCD_DrawAngleLine2(120,120,180+90-s*360/(12*60*60),40,WHITE );
LCD_DrawAngleLine2(120,120,180-90-s*360/(12*60*60),8,WHITE );
//分针
LCD_DrawAngleLine2(120,120,180+90-(s+1)*360/(60*60),52,BLACK );
LCD_DrawAngleLine2(120,120,180-90-(s+1)*360/(60*60),12,BLACK );
LCD_DrawAngleLine2(120,120,180+90-s*360/(60*60),52,WHITE );
LCD_DrawAngleLine2(120,120,180-90-s*360/(60*60),12,WHITE );
//秒针
LCD_DrawAngleLine2(120,120,180+90-(s+1)*360/(60),66,BLACK );
LCD_DrawAngleLine2(120,120,180-90-(s+1)*360/(60),18,BLACK );
LCD_DrawAngleLine2(120,120,180+90-s*360/(60),66,WHITE );
LCD_DrawAngleLine2(120,120,180-90-s*360/(60),18,WHITE );
//整点报时
if(s%3600==0) BEEP_OUT(2);
HAL_Delay(1000);
}
}