项目完成功能:
- 
时间显示功能,能显示单片机中记录的时间。其时间可以用按键修改
 - 
整点报时功能,
 - 
根据重力调整时钟位置,整个时钟的会随着器件的转动而发生相应的改变。
因为数字是由字库显示的。所以数字和字符的朝向不能改变。
 - 
按键对应不同的功能:
- 
调节时针
 - 
未定义
 - 
未定义
 - 
调节时针
 
 - 
 
所用板子资源介绍:
- 
定时器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); 
}
}