基于STM32F103模拟时钟
基于STM32F103的可设置时间、整点报时的模拟时钟,整点的时候可以通过板上的蜂鸣器以声音报时;转动板子,LCD屏上的时钟自动跟着旋转
标签
嵌入式系统
STM32
显示
模拟时钟
你家祖坟酱
更新2021-02-26
1215

项目完成功能:

  1. 时间显示功能,能显示单片机中记录的时间。其时间可以用按键修改

  2. 整点报时功能,

  3. 根据重力调整时钟位置,整个时钟的会随着器件的转动而发生相应的改变。

    因为数字是由字库显示的。所以数字和字符的朝向不能改变。

  4. 按键对应不同的功能:

    1. 调节时针

    2. 未定义

    3. 未定义

    4. 调节时针

所用板子资源介绍:

  1. 定时器3

  2. LCD——软件模拟SPI协议

  3. 按键——外部中断

  4. MPU6050——I2C协议

  5. 蜂鸣器——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);


}

}

附件下载
233.hex
下载文件
团队介绍
南京工业大学浦江学院/计算机与通信工程学院
团队成员
姚硕
(一个大三的秃头老)
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号