3345|2

275

帖子

4863

TA的资源

五彩晶圆(初级)

楼主
 

一个单片机程序性能优化的小例子(转) [复制链接]

一个单片机程序性能优化的小例子
好久没玩51了,昨天帮人看一个点阵屏的程序
屏是64*16的
用2片138做行选择(8*2=16),用8片4094做列输出(8*8=64)
原来程序的关键数据发送部分如下


  1. void xianshi()
  2. {
  3. unsigned char out_data = 0xff;
  4. unsigned char i,j;

  5. for (j=0;j<16;j++) //循环显示8行
  6. {
  7. out_OE = 0; // 输出先关了
  8. set_row(j); // 设置要显示的那一行
  9. for (i=0;i<8;i++) // 开始输出数据
  10. {
  11. CLK = 0;
  12. data0 = (bit)( ( show_array[j*2] >>i)& 0x01 );//输出对应那行的数据
  13. data1 = (bit)( ( show_array[j*2+1] >>i)& 0x01 );
  14. data2 = (bit)( ( show_array1[j*2] >>i)& 0x01 );//输出对应那行的数据
  15. data3 = (bit)( ( show_array1[j*2+1] >>i)& 0x01 );
  16. data4 = (bit)( ( show_array2[j*2] >>i)& 0x01 );//输出对应那行的数据
  17. data5 = (bit)( ( show_array2[j*2+1] >>i)& 0x01 );
  18. data6 = (bit)( ( show_array3[j*2] >>i)& 0x01 );//输出对应那行的数据
  19. data7 = (bit)( ( show_array3[j*2+1] >>i)& 0x01 );
  20. CLK = 1;// 时钟一次上升沿 数据被4094接收
  21. }
  22. out_OE = 1; // 可以打开输出了
  23. delay();
  24. }
  25. }
复制代码


开始测试屏的时候效果尚可
现在显示4个汉字发现屏闪得利害,分析原来为发送数据的时候过长,导致关显示的时候过长.
每次要对要发送的数据进行重新定位,而且下标还要用乘法再用加法才能得出
因为4094没有像595那样的二级锁存,发送数据期间必需要关显示
软件仿真一下,发现发送一次数据要4ms左右(晶体频率11.0592M)
因为有16行,16*4=64ms 按每秒刷30帧算,64*30=1920ms
超出1秒两倍多,于是出现:
延时太短,可以不闪,但亮度极低
延时加长,亮度上来了,但发现可以看出是一行一行显示的,不能用
此帖出自单片机论坛

最新回复

yjj
细活啊,哈哈!顶一个  详情 回复 发表于 2009-12-18 14:03
点赞 关注
 

回复
举报

275

帖子

4863

TA的资源

五彩晶圆(初级)

沙发
 
于是开始分析优化程序
首先



  1. show_array[j*2]

复制代码


这样的肯定不能用了,于是采用指针的方式,
于是,定义4个指向4个汉字的指针及8个当前行每一列的数据


  1. unsigned char *pd1,*pd2,*pd3,*pd4;
  2.     unsigned char sd1,sd2,sd3,sd4,sd5,sd6,sd7,sd8; // 当前行要显示的数据
复制代码


然后把这4个指针指向要显示的数据

  1.     pd1 = show_array;
  2.     pd2 = show_array1;
  3.     pd3 = show_array2;
  4.     pd4 = show_array3;
复制代码


然后再分别显示16行,为了缩短关显示的时间,我们在关显示前就要算出当前行要显示的数据,
并算出下一行要显示的数据

  1.     for (j=0;j<16;j++) //循环显示8行
  2.     {
  3.         sd1 = *pd1;
  4.         sd2 = *(pd1+1);
  5.         sd3 = *pd2;
  6.         sd4 = *(pd2+1);
  7.         sd5 = *pd3;
  8.         sd6 = *(pd3+1);
  9.         sd7 = *pd4;
  10.         sd8 = *(pd4+1);
  11.         pd1 += 2;
  12.         pd2 += 2;
  13.         pd3 += 2;
  14.         pd4 += 2;
  15.         out_OE = 0; // 输出先关了
  16.         set_row(j); // 设置要显示的那一行
  17. ..........................................
  18. }

复制代码


经仿真,在关显示前就算出本行要显示的数据,可以节省0.2ms
然后是单行输出部分进行改造,首先show_array[j*2+1]这样的不必再用了,直接使用sd1~sd8即可
然后也不再使用

  1. for(i=0;i<8;i++)
  2. {
  3.      (变量 >>i) & 0x01;
  4. }
复制代码


这样的判断方法,因为这样,CPU只能一位一位地移位,而且还要判断是否移够了
于是我们进行优化成

  1. for(i=0;i<8;i++)
  2. {
  3.     (sd1 & 0x01);
  4.     sd1 >>= 1;//自移一位并保存起来,不用每次都移N位了
  5. }
复制代码


整个程序优化得差不多了,仿真测试结果为,单行数据发送的时间为0.64ms
和原来4ms比较,6倍之多呀....
还有没有优化的地方呢?

  1. for (i=0;i<8;i++) // 开始输出数据
复制代码


可以优化成
  1. for (i=8;i>0;i--) // 开始输出数据
复制代码

原因是我用的C51 51有自减并判断非0的指令一条指令就搞定,
如果判断是否小于8,则要多条指令才能完成
那么

  1. for (j=0;j<16;j++) //循环显示16行
复制代码

可不可以也这样优化呢?
答案是可以,但实际测试结果是反而程序执行的时间太长了,
原因是下面我们用了到j这个变量

  1. set_row(j); // 设置要显示的那一行
复制代码

如果也优化成那样了,则要改成

  1. set_row(16-j); // 设置要显示的那一行
复制代码

多了一次运算,反而慢了....
于是这里就不能改了,
最终于测试结果: 单行发送数据耗时0.63ms (11.0592M晶体,12T普通51单片机)
0.63*16=10.08ms
10.08*30帧=302.4ms
302ms/1秒 = 0.3 也就是说刷30帧的时候,有30%的时候屏是关闭的,勉强能用了
所以,这屏要是用595来驱动的话,就没这个问题了,不过,算法亦然重要
此帖出自单片机论坛
 
 

回复

391

帖子

0

TA的资源

纯净的硅(高级)

板凳
 
细活啊,哈哈!顶一个
此帖出自单片机论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表