【stm32】开发过程精简板

本文介绍了作者开发的模拟时钟项目,包括时间显示、整点报时、重力感应及考研倒计时等功能。遇到的挑战如LCD刷新、蜂鸣器控制和时钟延迟初始化等。使用了STM32的定时器、LCD SPI、按键中断、MPU6050 I2C和串口通信技术。
摘要由CSDN通过智能技术生成

模拟时钟

AUTHOR:奈奎斯特不稳定

代码下载

本文档对应硬禾学堂寒假一起练(5)

项目完成功能:

  1. 时间显示功能,能显示单片机中记录的时间。其时间可以用上位机的特定的指令修改,格式如下

    "time:y%M%md%dYh%Hm%Ms%S"
    

    可以显示时间可以精确到秒,支持多次修改。

  2. 整点报时功能,具体响多少下,取决于给他的延时时间。KEY1按键关闭\开启蜂鸣器报警,左上角会显示其状态。

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

    注:由于数字是由字库显示的。所以数字和字符的朝向不能改变。

  4. 显示考研剩余天数。因为我是2022考研狗。所以需要时刻显示天数提醒我自己。按键4可以控制其开闭。

  5. SD卡图片显示函数。(需要提前将数组转化存入SD卡)不演示。

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

    1. 控制报时是否有效

    2. 关闭背光

    3. 开启背光

    4. 显示剩余考研天数(前提需要矫正时间)

      注:按键功能定义不能太长。程序可能会跑飞。

所用板子资源介绍:

  1. 定时器2、3、4
  2. LCD——SPI协议
  3. 按键——外部中断
  4. MPU6050——I2C协议
  5. SD卡——硬件SPI及FATF系统

按键:

按键是又硬件下拉的,所以初始化的时候只需要保持默认就行了。

image-20210121211705692

蜂鸣器:

image-20210121211613155

打算让他响1s,再停一秒的。结果发现好像就接上了一下,之后就没声了,需要耳贴近才能听到。后来我才意识到,这应该就是传说中的无源蜂鸣器。

image-20210113110831754

那只能再改了,还好用hal库的话比较方便。在群友的建议下。我打算使用4K的PWM使蜂鸣器响。

在修改的时候我好像悲催的发现PC10引脚好像不能直接输出PWM,我的天。

image-20210113110841631

由于程序资源占用太多,导致正常的延迟函数已经不能满足要求,所以只能在中断里操作了。引脚的模拟PWM频率在4KHz。

void MX_TIM4_Init(void)
{
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 72;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 250;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }

}


LCD刷新的问题

使用缓存数组,来显示图片,这样显示图片的效率能提升一倍。但是,发现如果需要准备缓冲数组,发现stm32的内存好像不足以支撑,也可能是我的操作方法的问题。所以我初始化了SD卡来拓展容量。可能使用SPI通讯的缘故,我发现随机写入SD卡数组的耗时实在是太长了。所以果断放弃了SD卡存放缓冲数组,改用局部刷新的方法

关于时钟延迟初始化

经过群友提醒,我发现这个板子由于是旁路时钟,所以会出现上电瞬间,时钟初始化失败。

image-20210119195607130

直接将HSE的timout改大一点就行

c60743b467ad4cd90879937fdfd08df

这里的数值改成1000U。上电后没有初始化失败的情况了。

MPU6050

只需要将I2C硬件初始化。然后按照数据手册,发送相对应的初始化命令就行了。本项目要求的精度不需要很高,按照默认的就行。项目的重点,是利用重力加速度在XY轴的分力的夹角来确定方向的。

网上有很多关于mpu6050姿态解算的案例。这里就不多做赘述。

    G_direction=-atan2(ax,ay);

上位机/下位机

现在加入下位机。之前有写过类似的,所以写起来应该会很快。现在加个串口接收,用DMA。

上位机发送代码格式请看下面的代码。

"time:y%M%md%dYh%Hm%Ms%S"
char *datare;

char time_begin[] = "time:";
char s_hour[] = "hour:";
char s_minument[] = "minument:";
char s_sec[] = "sec:";

int fresh_temp_sec;
void fresh_s_time(char *temp)
{
    for(fresh_temp_sec = -1; fresh_temp_sec<2; fresh_temp_sec++)
        RoundClock_CLR_ALL(WatchHour,WatchMiniute,WatchSec+fresh_temp_sec);
    while(*temp != '\0')
    {
        switch(*temp++)
        {
        case 'h':
            WatchHour = (*temp-'0')*10 + (*(temp+1)-'0');
            temp+=2;
            break;
        case 'm':
            WatchMiniute = (*temp-'0')*10 + (*(temp+1)-'0');
            temp+=2;
            break;
        case 's':
            WatchSec = (*temp-'0')*10 + (*(temp+1)-'0');
            temp+=2;
            break;
        case 'y':
            watch_date.years = (*temp-'0')*10 + (*(temp+1)-'0');
            temp+=2;
            break;
        case 'M': //月份
            watch_date.months = (*temp-'0')*10 + (*(temp+1)-'0');
            temp+=2;
            break;
        case 'd':
            watch_date.days = (*temp-'0')*10 + (*(temp+1)-'0');
            temp+=2;
            break;
        }
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    int i=0,m;
    m=strlen(time_begin);




    if(huart->Instance == USART2)
    {

        datare = (char *)rx_buffer;
        for(i=0; i<rx_len-m; i++)
        {
            if(strncmp(datare+i,time_begin,m)==0) //找到头
            {
                datare+=m+i;//取有效数据
                fresh_s_time(datare);
            }
        }

        memset(rx_buffer,0,sizeof(rx_buffer));//只能在中断里做,因为时间资源被占用完了。

        HAL_UART_Receive_DMA(&huart2,rx_buffer,BUFFER_SIZE);//重新打开DMA接收
    }
}

以上是我完成项目踩到的主要的坑。省略了很多部分。具体部分请看我的博客

_buffer));//只能在中断里做,因为时间资源被占用完了。

    HAL_UART_Receive_DMA(&huart2,rx_buffer,BUFFER_SIZE);//重新打开DMA接收
}

}


以上是我完成项目踩到的主要的坑。省略了很多部分。具体部分请看[我的博客](https://blog.csdn.net/ponieer/article/details/112935110)

原文非常冗长,读起来可能会有一定的障碍。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值