前言
大概半个月之前捣鼓了下利用STM32实现实时曲线显示,中间又做了一点小改进和扩充,在这里更新一下:
- 利用DMA进行缓冲区到LCD GRAM的像素数据搬运
- 效果更好的曲线绘制策略
代码可以在这里找到:<写得比较乱,望谅解( ´・ω・)ノ(._.`)
curve_chart.cgithub.com使用DMA进行像素搬运
利用STM32 DMA的M2M(Memory to Memory)模式,实现像素数据从外置SRAM的双缓冲区到LCD GRAM的搬移。只需要把数据源(SRAM)和终点(LCD-GRAM)的虚拟地址交给DMA,DMA控制器即可自动通知FSMC控制两个外设进行数据交换。
DMA初始化:
DMA_HandleTypeDef
双缓冲区像素更新:
void
注意到DMA一次最多搬运65535个数据,这里我们分多次发出DMA请求,一次搬运65535个WORD == 65535 * 2 个RGB565像素,分几部分将双缓冲区的像素刷新到LCD的GRAM中。在每一次DMA传输请求发出后,得等它传完才能进行下一次传输。
虽然CPU还是得在这里挂起等待,不过,,DMA传得快啊!ヽ(•̀ω•́ )ゝ
如果你的双缓冲区数据量小于65535 * 4个字节,甚至可以把DMA配置成CIRCULAR模式,或者利用一个定时器中断隔一段时间整体刷新一次,这样就不用在这里挂起等待啦。对于
320x240这种小屏幕甚至可以把整个屏幕区域开辟双缓冲区,然后利用DMA一直刷新就好,反正一次就能把所有像素搬完。没错是有这种操作的
但我用的屏分辨率比较高,就emmmmmmm
效果更好的曲线绘制策略
之前我们直接在数据点对应的位置处画一个点, 最多在它的邻域多画几个点。这样对于“平滑”的波形显示效果还行,但是对于竖直方向有快速变化的信号(比如方波),这种绘制策略会产生视觉上的不连续性,看起来很丑就是了XD
解决思路很简单粗暴,把两个数据点之间的垂直间隔补上即可,在局部产生一种阶梯状的填充,是不是有点像信号与系统里面学的离散采样点恢复连续信号使用的零阶保持╮( •́ω•̀ )╭
好啦我们上代码!
void
看到这里就要问了,这种绘制策略只是解决了y方向上数据点显示不连续的问题,那x方向呢?
我们默认传入的数据数组和绘图区域的宽度(即x方向上的像素数)一致,所以x方向我觉得十分OK!这不耍流氓吗,你怎么保证采集的数据刚好和图表的宽度一样多啊?
线性插值了解一下:
uint16_t
q15_t arm_linear_interp_q15(q15_t * pYData, q31_t x, uint32_t nValues)
这个函数是ARM DSP库自带的线性插值函数,除了16位的q15_t还有其他数据类型的版本
不管原始数据点数比显示区域的宽度多还是少,都可以利用这样的线性插值得到数量和图表宽度刚好匹配的显示数据。
总结与效果演示
进行了这两个地方的小改进,不管是速度还是效果都比之前的版本更好了
https://www.zhihu.com/video/987057417087148032
欢迎吐槽与提建议,一起交流学习!
ฅ(๑ ̀ㅅ ́๑)ฅ