求助,会C的帮忙看下,for循环的使用哪错了?

[复制链接]
 楼主| 雷影少年 发表于 2012-8-25 12:06 | 显示全部楼层
传上咱滴代码

  1. #include<reg51.h>

  2. typedef        unsigned char        u8;
  3. typedef unsigned int        u16;
  4. typedef        unsigned long        u32;
  5. #define        _TR0        10000                        //定义定时器初始值10ms
  6. #define        LINE        P1
  7. sbit R=P2^0;
  8. sbit CLK=P2^1;
  9. sbit STB=P2^2;
  10. u8        flag_10ms;
  11. u16        dat,dat0;

  12. /*--  新宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
  13.                 /*--  文字:  武  --*/
  14. u8 code seg[26][32]={};         //数组比较长就不传上来恶心人了

  15. /*缓冲数组(存储1个字模)便于读取数据*/
  16. u16        sbuf[16]={0};

  17. /*sbuf1初始化*/
  18. void sbuf_init()
  19. {
  20.         u8        i;
  21.         for(i=0;i<16;i++)
  22.         {
  23.            sbuf[i]=(sbuf[i]|seg[0][2*i+1]);
  24.            sbuf[i]=(sbuf[i]<<8)|seg[0][2*i];
  25.         }
  26. }

  27. /*更新缓冲区数据*/
  28. void sbuf_update()
  29. {
  30.         u8        i;
  31.         u16        temp0,temp1;
  32.         static        u8        m=0;                //存储左移字数
  33.         static        u8        n=0;                //存储左移次数

  34.         if(m<25)                        //未更新到最后一个字模
  35.         {
  36.                 if(n<16)
  37.                 {       
  38.                         for(i=0;i<16;i++)
  39.                         {
  40.                                 temp0=temp1=0;                                        //中间变量清零
  41.                                 temp0=temp0|seg[m][2*i+1];               
  42.                                 temp0=(temp0<<8)|seg[m][2*i];         //将前一个字代码赋给temp0
  43.                                 temp1=temp1|seg[m+1][2*i+1];
  44.                                 temp1=(temp1<<8)|seg[m+1][2*i];         //将后一个字代码赋给temp1
  45.                                 sbuf[i]=(temp0<<n)|(temp1>>(16-n));           //合成要显示的代码
  46.                         }
  47.                         n++;                                                                           //移位次数+1;
  48.                 }
  49.                 else
  50.                 {                                                                 
  51.                         n=0;                                                 //达到16次移位次数清0;
  52.                         m++;                                                 //移动字数加1
  53.                         sbuf_update();                                 //重新加载缓冲区字模
  54.                 }
  55.         }
  56.         else
  57.         {
  58.                 if(n<16)
  59.                 {       
  60.                         for(i=0;i<16;i++)
  61.                         {
  62.                                 temp0=temp1=0;                                        //中间变量清零
  63.                                 temp0=temp0|seg[m][2*i+1];               
  64.                                 temp0=(temp0<<8)|seg[m][2*i];         //将前一个字代码赋给temp0
  65.                                 temp1=temp1|seg[0][2*i+1];
  66.                                 temp1=(temp1<<8)|seg[0][2*i];         //将后一个字代码赋给temp1
  67.                                 sbuf[i]=(temp0<<n)|(temp1>>(16-n));           //合成要显示的代码
  68.                         }
  69.                         n++;                                                                           //移位次数+1;
  70.                 }
  71.                 else
  72.                 {                                                                 
  73.                         n=0;                                                 //达到16次移位次数清0;
  74.                          m=0;                                                //最后一个字已移出,移动字数清0
  75.                         sbuf_update();                                 //重新加载缓冲区字模
  76.                 }
  77.         }
  78. }

  79. void write(u16 dat)                                   //写入一个字节
  80. {
  81.         u8        i;
  82.         for (i=0;i<16;i++)
  83.         {
  84.                 dat=dat>>1;
  85.                 R=CY;
  86.                 CLK=0;
  87.                 CLK=1;
  88.         }
  89. }


  90. void main()
  91. {
  92.         EA =1;                                                //开中断
  93.         ET0 =1;
  94.         TMOD =0x01;
  95.         TH0 =-(_TR0/256);
  96.         TL0 =-(_TR0%256);
  97.         TR0 =1;
  98.         sbuf_init();
  99.         while (1)
  100.         {
  101.                 u8        i;
  102.                 if(flag_10ms<5)                                          //控制移动速度
  103.                 {
  104.                         for (i=0;i<16;i++)
  105.                         {
  106.                                 dat=sbuf[i];
  107.                                 write(~dat);                          //第i行字模写入595
  108.                                 LINE=i;                                                  //选择第i行
  109.                                 STB=1;
  110.                                 STB=0;                                                  //显示
  111.                          }
  112.                 }
  113.                 else                                                          
  114.                 {
  115.                         flag_10ms=0;
  116.                         sbuf_update();                                                //移动一次(1列)
  117.                 }
  118.         }
  119. }

  120. void time_10ms() interrupt 1                                   //每10ms中断一次
  121. {
  122.         TH0=-(_TR0/256);
  123.         TL0=-(_TR0%256);
  124.         flag_10ms++;
  125. }
欢迎拍砖哦~
您的砖头是我进步的源泉
不可怕的不是有错,而是明明错了还不知道在哪?
吃饭去了,下午学习下怎么用指针调用二维数组~
sfesdm 发表于 2012-8-25 12:33 | 显示全部楼层
从1加到100,1000,你可以逐个加,也可以用for循环加,逐个加你会耗费大量储存空间,for循环加可以省很多事,不过for循环会加大cpu的处理负担,具体的应用中,逐个加,还是用for循环,要根据具体情况而定。
 楼主| 雷影少年 发表于 2012-8-25 21:37 | 显示全部楼层
搞定

这是用指针的代码
  1. /*sbuf1初始化*/
  2. void sbuf_init()
  3. {
  4. u8 i=0;
  5. u8 *p;
  6. for(p=seg[0];p<seg[0]+32;p++)
  7. {
  8. sbuf[i]=p;
  9. sbuf[i]=(sbuf[i]<<8)|(*(++p));
  10. i++;
  11. }
  12. }

  13. /*更新缓冲区数据*/
  14. void sbuf_update()
  15. {
  16. u8 i,*p,*q;
  17. u16 temp0,temp1;
  18. static u8 m=0; //存储左移字数
  19. static u8 n=0; //存储左移次数
  20. if(m>25) m=0; //最后一个字已移出,左移次数清0
  21. else if(m==25) //最后一个字已移入,开始移入第一个字
  22. {
  23. p=seg[m];
  24. q=seg[0];
  25. }
  26. else
  27. {
  28. p=seg[m]; //确定要显示字的位置
  29. q=seg[m+1];
  30. }

  31. if(n<16)
  32. {
  33. i=0;
  34. for(p;p<&seg[m]+32;p++)
  35. {
  36. temp0=temp1=0; //中间变量清零
  37. temp0=temp0|(*p);
  38. temp0=(temp0<<8)|(*(++p)); //将前一个字代码赋给temp0
  39. temp1=temp1|(*q);
  40. temp1=(temp1<<8)|(*(++q)); //将后一个字代码赋给temp1
  41. sbuf[i]=(temp0<<n)|(temp1>>(16-n)); //合成要显示的代码
  42. // dat0=sbuf[i]; 测试代码
  43. q++;
  44. i++;
  45. }
  46. n++; //移位次数+1 ;
  47. }
  48. else //上一字已完全移出
  49. {
  50. m++; //左移字数加1
  51. n=0; //移位次数清0
  52. sbuf_update(); //重新加载缓冲区字模
  53. }
  54. }
我测试了下

使用指针时第一次调用sbuf_update用时5.358ms;占用date=58,xdate=0,code=1557;

不使用指针时第一次调用sbuf_update用时5.241ms;占用date=52,xdate=0,code=1717;

是不是因为我指针使用的有问题,书上不是说使用指针程序执行速度回提高吗?
 楼主| 雷影少年 发表于 2012-8-25 21:41 | 显示全部楼层
引用秋婷姐一句话"我觉得程序写的不难,难的是调试。。。"
我现在是深有体会啊~
程序个把小时就学出来了,调时往往要花上数倍甚至数十倍的时间。
怪不得都强调程序书写要规范~
chenbb8 发表于 2012-8-25 22:47 | 显示全部楼层
5MS?!!!!5us我都嫌长了
你应该没利用滑动滤波的原理或者是FIFO的更好,主要思想就是头指针和数据长度相结合。
每次只增加头指针,这个头指针虽然名字叫指针其实是一唯数组的下标~~
 楼主| 雷影少年 发表于 2012-8-26 00:02 | 显示全部楼层
本帖最后由 雷影少年 于 2012-8-26 09:22 编辑

51单片机,11.0592的晶振,5ms就是不到5000个机器周期,程序怎么优化都不可能到5us;以我目前的知识也做不了太多的优化了~
正在百度滑动滤波原理和FIFO,学习下看看~
chenbb8 发表于 2012-8-26 10:42 | 显示全部楼层
51也有快有慢的,比如STC比如C8051F~对于改进型的51程序执行时间的计算,不要相信软件仿真,要是纠结于5us的时间话,需要用定时器中的计数器来算,或者看反汇编和数据手册中每个指令的执行时间来计算~~反正效果超级好就是了。
#define SEG_NUM 22      //有多少个就填多少个
#define SEG_MAX  SEG_NUM*16    //22*16,这是一维数组的长度
#define SEG_LENG 16     //每次传送的元素数目

uint16_t Seg_Head = 0;  //一维数组的头指针
uint16_t Seg_Data = 0;  //一维数组的数组指针

uint16_t *pSeg = (uint16_t *) &seg[0][0];

#define WEIYI  ( if( ++Disp_Head >=  SEG_MAX )   {Disp_Head -= SEG_MAX} )

void Disp_On_LED(void)
{
……
    Seg_Data = Seg_Head;
……
        if( pSeg[Seg_Data] & 0x8000 ) R = 1;
        pSeg[Seg_Data] <<= 1;
         if( ++Disp_Data >=  SEG_MAX )   {Disp_Data -= SEG_MAX};
}

main()
{
WEIYI
Disp_On_LED();
……
}

上面的东西就是思路,显示不对的话就需要取字模软件的支持了。
LZ的单片机是8位的,请将上面的16位的指针pSeg改回8位的,每次位移+2。
或者在Disp_On_LED()中使用指针、位域强制类型转换成8位的用也行。
 楼主| 雷影少年 发表于 2012-8-26 10:58 | 显示全部楼层
试试看
O(∩_∩)O谢谢LS
chenbb8 发表于 2012-8-26 11:20 | 显示全部楼层
没有用编译器检查,我上面的代码貌似有BUG~~
比如if( ++Disp_Data >=  SEG_MAX )   {Disp_Data -= SEG_MAX};这句~
 楼主| 雷影少年 发表于 2012-8-26 16:51 | 显示全部楼层
本帖最后由 雷影少年 于 2012-8-26 16:52 编辑

仔细揣摩了下你的程序,若是按行显示的话感觉许多地方想不通
莫非你是按列显示的?数组里的数是按列存储的,话说我的东西已经焊好了,貌似只能按行显示吧~
若是按列显示的话只能改电路了~
按照当前电路的话,利用ls的思路可以写个上移或者下移程序。
不知是不是我的理解有误~
不过还是要O(∩_∩)O谢谢ls,现在有耐心看新手代码的DX不多了
20分全给你了哦~
chenbb8 发表于 2012-8-26 19:12 | 显示全部楼层
:loveliness:不是在做实验的吗~将字模改成列的形式发出去也就是图形扭转了90度而已
想要扭转回来的话可以牺牲Disp_On_LED(void)函数的效率,通过让显示程序变的臃肿来减少位移的时间,下面的程序同样没考虑8位机的优化
void Disp_On_LED(void)
{
    uint16_t Col_Tmp = 0x0001;   //用来和字模的列 相与的变量
……
    for( i = 16; i > 0; i--)             //外循环决定取字模中 列的那一个行
    {
        Seg_Data = Seg_Head;     //指向起始的位置


        for( j = 16; i > 0; i--)          //内循环遍历16个列
        {
            if( seg[Seg_Data] &  Col_Tmp ) R = 1;
            Seg_Data++;
        }

        Col_Tmp <= 1;                //更换另外一行,觉得方向颠倒了的话,Col_Tmp的左右移和Seg_Data的增减上要做调整
    }

}
由于在你的程序里显示部分是经常执行的,也就是说占用CPU时间的大头,因此以上的显示程序只能看下了~
不过倒是可以在不修改字模的情况下将做出显示的扭转效果。
另外使用指针并不能直接带来效率的提升,因为使用指针指向变量来操作变量的做法叫做间接访问,间接访问相对直接访问会在语法层次带来效率的降低。
但却可以使用更加先进灵活的技巧,从而带来几倍甚至几百倍的优化效果。
 楼主| 雷影少年 发表于 2012-8-26 19:39 | 显示全部楼层
指针访问是间接访问什么的我是知道的,我接触过汇编,间接访问在51里是占3个周期的,指针是间接寻址,使用起来比较方便~
我记得貌似在哪本书说指针可以提高程序效率的,但是却不免白为什么?
寻址发现貌似指针不能提高程序速度,但是能使程序更加简洁,代码执行效率更高
chenbb8 发表于 2012-8-26 20:14 | 显示全部楼层
有时间可以看下《C和指针》,看评论这是一本C入门的书,但我觉得还是有一点点C的基础再看会比较合适,因为有些地方讲的不够详细。
这本书讨论了很多程序优化的方法
 楼主| 雷影少年 发表于 2012-8-26 21:54 | 显示全部楼层
sedatefire 发表于 2012-8-27 11:03 | 显示全部楼层
路过,小伙子不错,兢兢业业,孜孜不倦...
加油...
 楼主| 雷影少年 发表于 2012-8-27 11:39 | 显示全部楼层
还要斑竹多多批评啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部