完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
由于到货比较慢。所以之前我就用别的器件代替试做了一下第一个,重力时钟。等到到货的时候我已经差不多做出来了。所以我现在非常清楚需要哪些资源。
总共要初始化的部分:一个I2C总线、一个SPI总线、两个定时器、四个GPIO初始化上拉、一个串口、蜂鸣器 还是挺简单的哈。 大一寒假开始学长让我们自学32,当作进实验室的考核。进了实验室后,也都是凭着兴趣在学。现在大三了。感觉这个板子上的还好。有些时候遇到那种看不到的坑。那是最难受的。整一个月都整不出来的那种。 与mpu6050通讯的总线I2C MPU6050以及BH1750(I2C) 两个定时器: 我喜欢用定时器中断完成我需要的任务 另外一个定时器提供1ms的标准时钟,用于更新实时时间。 四个GPIO的初始化 用于按键的闲杂功能。 这几个引脚在硬件上都被上拉了。所以,理论上是不需要初始化上拉的。但是我还是决定,初始化上拉一下。然后低电平检测。 KEYS:(这个按键分布真是一点也不友好啊) 说实话,我是没有用过LCD显示屏的,之前的项目中也是用的OLED代替LCD显示屏。所以,我预测在LCD显示屏上开发的是时间将会最久。 串口(USART2) 使用DMA通讯,用DMA的话,占的时钟资源比较少。主要是打算使用串口,修改时钟数据。为此我特地写了一个小型的下位机。上位机用python获取当前的时间。然后通过串口发送到单片机。这样改的时间就会比较准确。用按键改时间实在是太鸡肋了。 硬禾给的下载器上有一路的USART,那就不用多余的线,就非常完美。 PA3:RX PA2:TX 蜂鸣器(PC10) 用于整点报时。PC10.我模电学的不是很扎实。这个电路应该是给低电平蜂鸣器不响。给高电平蜂鸣器响吧。 那就下拉输出初始化。 对我这个方案有些不理解的可以看一下我之前的心得,也在这个文件夹里。 好了,方案已经出来了,现在开干。 首先,先初始化所有的资源。用CUBEMX就是这么自信。不会出错。定时器和串口都要中断使能。 时钟 常规的72M 定时器 定时器2:7200的分频,记100个数。就是10ms,优先级设为一,其他都不变 定时器3:7200的分频,记10个数。就是标准的1ms I2C2总线 串口初始化 初始化为异步串口,其他不用动,添加DMA,RX,TX都要添加。以防之后有可能要用到。 四个GPIO 初始化就行。上不上拉的都无所谓了。 蜂鸣器 初始化就完事了,电路中本身就下拉了。 SPI初始化 这里是我最不熟练的部分了,所以初始化起来。我打算小心再小心。首先上网搜资料。嘿嘿。 在网上搜了一圈资料之后果然没有现成的。这个SPI就先不初始化了。以后再说。测试一下各个功能是否正常。 模块验证 mpu6050验证通过 串口验证通过 蜂鸣器 打算让他响1s,再停一秒的。结果发现好像就接上了一下。之后就没声了。而且需要耳贴近才能听到。后来我才意识到。这应该就是传说中的无源蜂鸣器。 那只能再改了,还好用hal库的话比较方便。在群友的建议下。我打算使用4K的PWM使蜂鸣器响。 在修改的时候我好像悲催的发现PC10引脚好像不能直接输出PWM。我的天。 现在我能想到的是利用定时器四来翻转IO达到输出PWM的目的。哎呀,干嘛这么麻烦。用延时函数凑合得了。 经过了一夜的纠结后,我还是打算用TIM4的定时器中断来产生PWM波脉冲。打算利用他的PWM模块产生的中断。进入来操作IO口。 搜罗了网上的资料之后,发现无源蜂鸣器的最佳频率为3K-4K之间。取了一个裕度后,我打算将PWM的频率设置在5K左右。即0.2MS 利用公式:Tout = ((ARR + 1)*(PSC + 1)) / Tclk 非常容易计算出来。Tout = 0.2 *10-3s、ARR+1 = 2000、Tclk = 72 *106、 PSC+1 = 7(算出来是7.2由于不能取小数,所以我取7) 为了贪图方便。我就把蜂鸣器的操作都放在了主函数里面,不高兴再开一个文件了。 刚刚,我突然发现我好像想多了,我想着改他的占空比了。这种无源蜂鸣器干嘛改占空比啊。直接在中断服务函数中翻转电平不久好了? 所以,最终的方案啊,不分频,直接修改ARR来改变他的频率。 至此,蜂鸣器验证完毕。 LCD屏幕验证 在网上找了好多资料,学习了DRAM等一些莫名其妙的操作后,突然想起来。原理图上好像有对应的型号。将型号输入到某宝里说不定能搜到对应的资料。 结果真搜到了一个对应的资料。不知道效果怎么样。 看了一圈例程,没有RBT的例程,真的非常可惜,随便打开一个看看。非常轻松的读出。程序用的是软件SPI。先在cube中初始化。 经过了半天的修改移植,总算是能显示图片了。但是文字还是不能显示。不过能显示图片就说明能打点了。那就好办了。先把我之前拿到的OLED的API拿出来修改一下。 改了半天,发现要把整个工程都改过来太麻烦了。我打算创建以LCD_API。文件里面包含了所有的需要用到的函数。 经过了一个晚上的奋斗。总算使能把时钟显示出来了。明天找个时间。把表盘大小和数字改一下。 遇到的问题2(刷新太慢) 那最常见的方法,用空间换时间呗。 现在是可以成功显示时钟了。但是也遇到了一个问题。就是LCD的刷新率太慢。导致画面有停顿感。所以我打算用显示图片的方法。来些屏幕。但是我现在对LCD的数组不是很清楚。不知道他的数组是怎么来显示颜色的。所以主要任务是把数组整明白。 先用Image2lcd软件提取一副240*240的图像试一下。看看提取出来的数组会有多大。 这里随便引入一张图片, 在photoshop中转换成240*240的彩色图片。 将图片在LCD中过一遍: const unsigned char gImage_LCD_TEMP[115200] 出来了115200大的数组。也就是这个数组里面有115200个数据。 用计算机算一下:240 * 240 * 2 = 115200 ,也就是说。LCD屏幕一个像素点占两个char型。也就是16位。 。。。啊,感觉好复杂。要写算法的话。啊啊啊。 现在先试一下做个一8*8的黑白图片 就像这样 转换后: const unsigned char gImage_xuexi[128] = { /* 0X00,0X10,0X08,0X00,0X08,0X00,0X01,0X1B, */ 0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF, 0XFF,0XFF,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF, 0XFF,0XFF,0XFF,0XFF,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF, 0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF, 0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF, 0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0XFF,0XFF,0XFF,0XFF, 0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00,0XFF,0XFF, 0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X00, }; 可以很清楚得窥见。黑色为0x00,白色为0xff 在我将一张图片塞进程序里之后我突然发现。stm32好像没有那么多的空间塞一张图片。 仔细算一下,115200*8 = 921600 = 1110 0001 0000 0000 0000b说不定真超了。 不得不说。这坑啊。哎。 现在得解决方案有两个: 做一个sd卡的外设。 在原有程序的基础上修修补补 我选择后者。因为懒。我打算将会旋转的部分刷新。也就是在刷新之前,填成黑色。 看起来这个方案失败了。果然不出所料的在闪。 看起来不得不使用三位数组来完成这个任务了。 看了一下三维数组的介绍。发现这里图形数组的用法和三维图形如出一辙。所以我打算多花点时间使用方案2. 看了一下红色是 0xF800 这里稍微记一下。一会儿会用到。 好了初始化SD卡。还好我之前做过的BADAPPLE有用到SD卡。 不对!!!这个RBT没有SDIO接口。我靠真的到处都是坑啊。 在经历了一天的挣扎后。总算,时钟是有点象样了。但是。这个时钟不能旋转。也就是说。不得不用缓存数组。而要用缓存数组。则不得不用SD卡。 经历了几天的挣扎。我还是决定使用SD卡。 那有了SD卡这个外部存储之后做事就变得简单了。 先写一个图片缓存函数240* 240* 2 = 115200 讲真,这个大小用串口发送数据。的话要1/8秒才能完成。换句话说。就是8帧的刷新率。就这刷新率。也最多能当个钟用了 就是最基本的打点函数。 里面有我关于图片数组的见解。我在这里简单重复一下。现在需要准备一个三维数组。分别是长度、宽度和深度(颜色)。在c语言中。如果要定义对数组处理的函数。就需要弄清楚指针和数组的关系。 以二位数组为例:如果要处理char类型二位数组。可以定义一个指向char的指针。然后将二位数组得到首地址赋给指针。然后对指针进行操作。这样做可以,但是不严谨,而且繁琐:首先二位数组的首地址是指向数组的指针,而不是指向char的指针。直接赋值并不严谨。其次,需要知道数组和指针的增量关系然后构筑算法来解决这个问题。繁琐。 也可以使用二重指针。定义一个固定深度的指针。指向数组指针。到时候取用的时候只需要按照数组的表达方式就可以取到对应的值。这种方法的缺点是。你必须知道你要处理的指针的深度。 还有一些别的赋值方法。这里就不介绍了。参照上面的图片看吧。 在函数的多维数组中,第一括号知识表明这是一个指针,里面的内容可以省略外,后面的括号里的内容都不能省略。 由于一副图片太大,以至于stm32没有足够的RAM来存放这张图片,所以需要直接在内存卡上直接处理数组 相信大叫都知道文件这种东西。但是要仔细说明文件的本质,这还是有点难度的。所以在这之前,先要明白文件是什么。 SD卡的读取思路 我是这样想的,以3行为一个单位。循环读取80次就是240行。每一次循环把3行的数据打印在屏幕上。每一行的数据是240*2.一次读取 240 * 3 * 2 = 1440为1k多的数据。还是可以接受的。 现在打算把图片的数据存在SD卡中。然后用f_read读取数据。 现在能隐约看到原图了。 但是图片好像是有点彩色上的失真。 和原图对比一下 我换了一种编写文件的方式。发现多少有丢包的现象不知道是为什么 关于操作SD卡中数组的事情。我就直接放在了LCD.c这个文件里了。 SD卡显示图片失败。我把原因归结于:刷新太耗费时间。导致SD卡指针忙碌。 刚刚我测试了一下,结果发现。如果把数组放在SD卡里面读写实在是太慢了。整个过程有27秒。这个方法果断放弃。 经过实验证明。用这个LCD屏不闪是不可能的了所以我要做的,就是尽量让他不要闪 关于局部刷新 由于我使用的是局部刷新。如果刷新速度太快。会导致画面闪烁。而如果刷新太慢又会导致有小点残留在画面当中。这是我不能仍受的。所以我打算把那一块用矩形填起来。 要按照时间的规律去刷新的话。也能节省一部分资源。不能按照时间刷新了看来。只能按照坐标刷新。对应的分针在哪个块就刷新哪快。 关于时钟延迟初始化 经过群友提醒,我发现这个板子由于是旁路时钟。所以会出现上电瞬间。时钟初始化失败。 直接将HSE的timout改大一点就行 这里的数值改成1000U。上电后没有初始化失败的情况了。 现在时钟刷新已经算是流畅了,写上位机 现在加入下位机。之前有写过类似的。所以写起来应该会很快。现在加个串口接收。用DMA。 上位机发送代码格式请看下图 头文字为 :time: 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 != ‘ ’) { 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接收 } } 蜂鸣器的问题: 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(); } } 所以延时1s为4000个数 按键问题 在开发的过程中,发现由于过程工程所使用的时钟资源太多了。导致WHILE中的时钟资源已经很少了。所以我打算更改按键扫描的策略。改用外部中断。 还有好多以前在while里面能解决的问题。都只能放在中断里面了。资源消耗太多。 完事收工 完成功能介绍: 时间显示功能。能显示单片机中记录的时间。其时间可以用上位机的特定的指令修改。格式如下 “time:y%M%md%dYh%Hm%Ms%S” 可以显示时间可以精确到秒。支持多次修改。 整点报时功能。具体就是到了几点就会响几下。可以通过按键来取消报点功能。报点功能是否有效。屏幕左上角会显示。 根据重力调整时钟位置。注:由于数字是由字库显示的。所以数字和字符的朝向不能改变。 整个时钟会随着重力的改变而改变方向。 显示考研剩余天数。因为我是2022考研狗。所以需要时刻显示天数提醒我自己。由于天数计算的函数没有设计完全。题目中也没有要求。所以就不显示了。 SD卡图片显示函数。(需要提前将数组转化存入SD卡)不演示 按键对应不同的功能: 控制报时是否有效 关闭背光 开启背光 未定义 注:按键功能定义不能太长。程序可能会跑飞。 由于要保证屏幕的刷新率和反应速度,很多地方我都进行了简化处理。如果想加入更多的功能。比如卡尔曼滤波。可以考虑减小屏幕的刷新率。 所用板子资源介绍: 定时器2、3、4 LCD——SPI协议 按键——外部中断 MPU6050——I2C协议 可以显示时间可以精确到秒。支持多次修改。 整点报时功能。具体就是到了几点就会响几下。可以通过按键来取消报点功能。报点功能是否有效。屏幕左上角会显示。 根据重力调整时钟位置。注:由于数字是由字库显示的。所以数字和字符的朝向不能改变。 整个时钟会随着重力的改变而改变方向。 显示考研剩余天数。因为我是2022考研狗。所以需要时刻显示天数提醒我自己。由于天数计算的函数没有设计完全。题目中也没有要求。所以就不显示了。 SD卡图片显示函数。(需要提前将数组转化存入SD卡)不演示 按键对应不同的功能: 控制报时是否有效 关闭背光 开启背光 未定义 注:按键功能定义不能太长。程序可能会跑飞。 由于要保证屏幕的刷新率和反应速度,很多地方我都进行了简化处理。如果想加入更多的功能。比如卡尔曼滤波。可以考虑减小屏幕的刷新率。 所用板子资源介绍: 定时器2、3、4 LCD——SPI协议 按键——外部中断 MPU6050——I2C协议 SD卡——硬件SPI及FATFS |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1561 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1501 浏览 1 评论
933 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
665 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1555 浏览 2 评论
1847浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
609浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
503浏览 3评论
507浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
488浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-10 13:49 , Processed in 0.623698 second(s), Total 75, Slave 59 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号