有没有一款占用内存超小的抢占式RTOS?
我有一个程序,使用的是STC32G12K128芯片,35M频率,程序编译后占用的资源比较多,如下Program Size: data=13.7 edata+hdata=3737 xdata=7684 const=1609 code=31953
creating hex file from ".\Obj\main"...
".\Obj\main" - 0 Error(s), 12 Warning(s).
edata使用了3737,xdata使用了7684,因为要驱动一个P3.75的LED大屏,35张模组,所以30张模组在xdata在,5张在edata中,以二维数组方式声明的内存
在这种情况下,还能上哪一款实时操作系统呢?
目前来说,任务如下:
刷新任务,函数需要10ms,那么每秒60HZ的话,需要每16ms执行1次刷新函数,如果17ms执行1次的话刷新率不到60,则肉眼可见的屏闪,有时虽然频率达到60hz,但刷新时快时慢屏也会闪,所以要想屏不闪,必须准时执行该任务!!
有3个任务,执行时间需要5ms,执行间隔100ms左右不影响
有1个任务,执行时间为0~2ms时间不定,间隔必须10ms
还有几个执行时间为0ms的任务,不影响
如果采用普通的 while(1){}的方式来写的话,9+4*3+2=23ms,1000/23=43HZ,明显不够,屏幕1闪1闪的
我目前使用的是官方的至简无错 改进版 调度方案,优先级最高的刷新任务,每16ms执行1次,3个需要5ms的任务,每80ms执行1次,但不是同时执行,也就是说分别计数到25,41,57时执行
虽然 这样改进后,屏幕稳定多了,但是碰到那个10ms间隔的任务就完蛋了,因为必须10ms执行1次,且执行的时间不确定,有时需0ms,有时需1ms,有时需2ms,导致刷新任务偶尔延误,屏偶尔闪烁
请问这种情况下,有没有一种占用内存在1k左右的抢占式RTOS呢?只要有最简单的抢占式调度就行了,不需要任务间的通信功能。。。
本帖最后由 tzz1983 于 2024-5-30 11:21 编辑
一种用DMA刷新模组的办法:
模组显示驱动是用串行传输数据的,
单路串行信号分别为:
DAT: //数据
CLK: //同步串行时钟
其它辅助信号:
LE: //数据锁存
OE://输出允许
A:B:C:D: //行扫描地址.
为了显示多种颜色和提高效率,采用多路串行数据传输
多路和单路相同,只是增加了DAT位,例如一个 HUB75 接口包含了6个数据端口:
R1://数据
G1://数据
B1://数据
R2://数据
G2://数据
B2://数据
CLK: //同步串行时钟
其它辅助信号:
LE: //数据锁存
OE://输出允许
A:B:C:D: //行扫描地址.
STC32系列有LCM接口,并且可以DMA,稍加利用就可以用于模组的驱动,并且是DMA驱动,让CPU解放出来!
具体方法是:
1. 把LCM驱动的WR信号用作串行口的CLK信号,如下图
2. LCM的16位数据口用作串行数据口,这样一次CLK就可以同时传输16位数据。
3. 把要显示的数据按照顺序放在XDATA中,然后启动DMA。很简单,并不难。这样就可以大幅减轻CPU的压力。
4. 做到以上几点,静态画面刷屏的事情基本就不用CPU管了,弄个PWM定时DMA传输.
5. CPU的主要工作就是更新XDATA中的显示数据,如果是静态画面,CPU将无事可做,CPU使用率可控制在2%以内!
6. 当然动态画面还是有压力的,主要因为要配合DMA格式,写点(也就是写XDATA)时可能要有相应的算法。
其它技巧:
1. 利用PWM中断来产生行扫描定时,为什么用PWM而不是用定时器?
因为PWM可以自动控制OE端,让屏幕的亮度无级调,效果很好!
2. 用或不用RTOS都没有关系,因为任务非常少,可以直接用一个低级中断来代替任务,更高效。
另外60HZ帧率实在是太低了,这也是最低的要求,仅人眼观察问题不大,
但是摄像机就拍不出来了,抖得很厉害,或者拍到的是一行行的乱七八糟。
我是做交通信号类的产品,要求比较高,我一般都做到200HZ以上的帧率,
资源允许时做到400HZ以上,这样就是摄像机拍出来,也是完好的图像
我也做模组相关的产品,以上是我的心得, 希望能帮到你
我曾用STC32G做一款产品,显示静态画面时,CPU使用率可控制在2%以内!
当然只是静态画面,动画还是有压力的,主要压力是不断更新XDATA中的显示内容。
tzz1983 发表于 2024-5-30 09:22
一种用DMA刷新模组的办法:
模组显示驱动是用串行传输数据的,
谢谢回复,,我受到坛友“QQ624***”的启发,我用一个24位自动重载的定时器,16ms中断,把刷新代码放到中断中,就搞定了,,结果30M晶振跑这个程序,屏一点也不闪,其它任务通通放到while(1)中,不停的排队循环执行即可,只是那个10ms执行1次的任务,现在大于10ms了,估计再弄个10ms定时器就搞定了。。。
看来大部分其实根本用不到rtos,,只要硬件定时器足够多的话,比上rtos简单,呵呵!
不过你的回复我以后要去研究的,谢谢!~ tzz1983 发表于 2024-5-30 09:22
一种用DMA刷新模组的办法:
模组显示驱动是用串行传输数据的,
我又仔细看了一下你的回复,60HZ的刷新率,只是人眼看不出来,用手机拍,还是1行1行的,下次试试你说的DMA刷新技巧,,我的程序有3个任务分别占用5ms时间,就是用来更新xdata中的数据所消耗的时间
【新提醒】视频教学《USB型 1T 8051 单片机原理及应用-STC8H8K64U》,山东大学陈桂友教授 - 视频教学,《单片机原理及应用》教学改革及实践研讨会,实战技术交流会,会务通知 国芯技术交流网站 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)
【新提醒】视频教学《USB型 1T 8051 单片机原理及应用-STC8H8K64U》,山东大学陈桂友教授 - 视频教学,《单片机原理及应用》教学改革及实践研讨会,实战技术交流会,会务通知 国芯技术交流网站 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)
【新提醒】任务调度方法,【无错,至简】!“多任务分时调度” - uCOS/FreeRTOS,GUI-uGFX/U8g2, 文件系统, 国产RTOS, 实时操作系统 国芯技术交流网站 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)
神农鼎 发表于 2024-5-30 13:09
【新提醒】视频教学《USB型 1T 8051 单片机原理及应用-STC8H8K64U》,山东大学陈桂友教授 - 视频教学,《 ...
非常感谢,,提供了这么详细的视频教程。。 神农鼎 发表于 2024-5-30 13:09
【新提醒】视频教学《USB型 1T 8051 单片机原理及应用-STC8H8K64U》,山东大学陈桂友教授 - 视频教学,《 ...
最近在学习这系列视频,正好学了DMA读写串口的视频,发现DMA方式串口接收数据的时候,很容易丢失数据啊。。。
#include "stc/STC32G.h"
#include "stdio.h"
#include "intrins.h"
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
#define MAIN_Fosc 22118400L //定义主时钟(精确计算115200波特率)
#define Baudrate1 115200L
bit DmaTxFlag;
bit DmaRxFlag;
u8 xdata DmaBuffer;
void UART1_config(u8 brt); // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
void DMA_Config(void);
void Delay90us(void);
void UartPutc(unsigned char dat)
{
SBUF = dat;
while(TI == 0);
TI = 0;
}
char putchar(char c)
{
UartPutc(c);
return c;
}
//========================================================================
// 函数: void main(void)
// 描述: 主函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void main(void)
{
u16 i;
WTST = 0;//设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXFR = 1; //扩展寄存器(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
P0M1 = 0x00; P0M0 = 0x00; //设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
P1M1 = 0x00; P1M0 = 0x00; //设置P1.1、P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V), P1.1在PWM当DAC电路通过电阻串联到P2.3
P2M1 = 0x00; P2M0 = 0x00; //设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
P3M1 = 0x00; P3M0 = 0x00; //设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
P4M1 = 0x00; P4M0 = 0x00; //设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
P5M1 = 0x00; P5M0 = 0x00; //设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
P6M1 = 0x00; P6M0 = 0x00; //设置为漏极开路(实验箱加了上拉电阻到3.3V)
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
for(i=0; i<256; i++)
{
DmaBuffer = i;
}
UART1_config(1); // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
printf("STC32G UART1 DMA Test Programme!\r\n");//UART1发送一个字符串
DMA_Config();
EA = 1; //允许总中断
DmaTxFlag = 0;
DmaRxFlag = 0;
while (1)
{
if(DmaRxFlag)
{
DmaRxFlag = 0;
Delay90us();//模拟被其它中断 或 其它后台程序占用90us的时间,然后再开启DMA接收数据,则会丢失1个字节的数据
DMA_UR1R_CR = 0xa1; //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
}
}
}
void Delay90us(void) //STC32G @22.1184MHz
{
unsigned long edata i;
_nop_();
_nop_();
i = 496UL;
while (i) i--;
}
//========================================================================
// 函数: void DMA_Config(void)
// 描述: UART DMA 功能配置.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2021-5-6
//========================================================================
void DMA_Config(void)
{
DMA_UR1T_CFG = 0x80; //bit7 1:Enable Interrupt
DMA_UR1T_STA = 0x00;
DMA_UR1T_AMT = 20; //设置传输总字节数(低8位):n+1
DMA_UR1T_AMTH = 0x00; //设置传输总字节数(高8位):n+1
DMA_UR1T_TXAH = (u8)((u16)&DmaBuffer >> 8);
DMA_UR1T_TXAL = (u8)((u16)&DmaBuffer);
DMA_UR1T_CR = 0xc0; //bit7 1:使能 UART1_DMA, bit6 1:开始 UART1_DMA 自动发送
DMA_UR1R_CFG = 0x80; //bit7 1:Enable Interrupt
DMA_UR1R_STA = 0x00;
DMA_UR1R_AMT = 20; //设置传输总字节数(低8位):n+1
DMA_UR1R_AMTH = 0x00; //设置传输总字节数(高8位):n+1
DMA_UR1R_RXAH = (u8)((u16)&DmaBuffer >> 8);
DMA_UR1R_RXAL = (u8)((u16)&DmaBuffer);
DMA_UR1R_CR = 0xa1; //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
}
//========================================================================
// 函数: void UART1_config(u8 brt)
// 描述: UART1初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART1_config(u8 brt) // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
{
u16 dat = (u16)(65536UL - (MAIN_Fosc / 4) / Baudrate1);
/*********** 波特率使用定时器2 *****************/
if(brt == 2)
{
S1BRT = 1; //S1 BRT Use Timer2;
T2R = 0; //Timer stop
T2_CT = 0; //Timer2 set As Timer
T2x12 = 1; //Timer2 set as 1T mode
T2H = dat >> 8;
T2L = dat;
ET2 = 0; //禁止中断
T2R = 1; //Timer run enable
}
/*********** 波特率使用定时器1 *****************/
else
{
TR1 = 0;
S1BRT = 0; //S1 BRT Use Timer1;
T1_CT = 0; //Timer1 set As Timer
T1x12 = 1; //Timer1 set as 1T mode
TMOD &= ~0x30;//Timer1_16bitAutoReload;
TH1 = dat >> 8;
TL1 = dat;
ET1 = 0; //禁止中断
TR1= 1;
}
/*************************************************/
SCON = (SCON & 0x3f) | 0x40; //UART1模式, 0x00: 同步移位输出, 0x40: 8位数据,可变波特率, 0x80: 9位数据,固定波特率, 0xc0: 9位数据,可变波特率
//PS= 1; //高优先级中断
// ES= 1; //允许中断
REN = 1; //允许接收
P_SW1 &= 0x3f;
P_SW1 |= 0x00; //UART1 switch to, 0x00: P3.0 P3.1, 0x40: P3.6 P3.7, 0x80: P1.6 P1.7, 0xC0: P4.3 P4.4
}
//========================================================================
// 函数: void UART1_DMA_Interrupt (void) interrupt 50/51
// 描述: UART1 DMA中断函数
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2021-5-8
// 备注:
//========================================================================
void UART1T_DMA_Interrupt(void) interrupt DMA_UR1T_VECTOR
{
if (DMA_UR1T_STA & 0x01) //发送完成
{
DMA_UR1T_STA &= ~0x01;
}
if (DMA_UR1T_STA & 0x04) //数据覆盖
{
DMA_UR1T_STA &= ~0x04;
}
}
void UART1R_DMA_Interrupt(void) interrupt DMA_UR1R_VECTOR
{
if (DMA_UR1R_STA & 0x01) //接收完成
{
DMA_UR1R_STA &= ~0x01;
DmaRxFlag = 1;
//开始发送数据
DMA_UR1T_AMT = DMA_UR1R_AMT; //数据长度
DMA_UR1T_CR |= 0x60; //开始发送数据
}
if (DMA_UR1R_STA & 0x02) //数据丢弃
{
DMA_UR1R_STA &= ~0x02;
}
}
执行结果:
当以DMA方式接收串口数据时,能否增加配置,循环接收数据,比如我缓存区设100,接50就产生就接收完成,开始接收标志位不清零,模块还可以继续接收数据,把接收到的数据保存到缓存区后面50字节中,如此循环接收
还有,DMA本身是为了减少串口中断次数的,而示例中有个超时程序,5ms没有接收到数据则停止,这样的话反而得开3个中断,定时器中断,串口中断,DMA中断,比没有DMA方式所开的中断更多了
这时能不能内部做个超时处理呢?比如缓存区设为100,接收到第1个字符开始记时,自动按波特率算出接收1个字符需要的时间,中间有超过n个字符的时间没有收到数据则中断,让用户去处理数据,n可以配置0,1,2,3
乘简 发表于 2024-6-13 16:50
最近在学习这系列视频,正好学了DMA读写串口的视频,发现DMA方式串口接收数据的时候,很容易丢失数据啊。 ...
这个代码用了比较久了,已稳定,可以参照一下, UART1_DMA目标机型, STC32G
页:
[1]
2