搜索
bottom↓
楼主: machao

本次实践操作考核题,请有兴趣的给个简单代码—-- 157楼给出目前最佳的代码

[复制链接]

出0入0汤圆

发表于 2011-1-22 00:31:54 | 显示全部楼层
测试平台:ATmega16
测试工具:AVR Dragon
测试方法:实时硬件仿真

测试环境:AVR Studio + CodeVision AVR

测试目的:验证millwood0的时间计数器操作方法对定时精度的影响

测试描述:ATmega16主频1MHz,采用两个定时器——TIM0和TIM2,其中TIM0定时器初值设置为0x80,工作模式为溢出中断,开启中断服务函数;TIM2定时器工作模式为溢出中断,不设初值,用于监测TIM0的定时精度。每次进入TIM0中断服务函数时,先使用millwood0的方法为TIM0赋初值,然后在NOP处设置断点,观察TIM2中TCNT2的计数值,多次测量,取TCNT2的差值以验证定时精度。

测试结果:


(原文件名:1test.jpg)


(原文件名:2test.jpg)


(原文件名:3test.jpg)


(原文件名:4test.jpg)


(原文件名:5test.jpg)


(原文件名:6test.jpg)

检测TCNT2结果:
第1次:0x88;
第2次:0x0C;
第3次:0x8E;
第4次:0x12;
第5次:0x94;
第6次:0x18.

第1次和第2次之间的差值:0xFF-0x88+0x0C=0x83
第3次和第2次之间的差值:0x8E-0x0C=0x82
第4次和第3次之间的差值:0xFF-0x8E+0x12=0x83
第5次和第4次之间的差值:0x94-0x12=0x82
第6次和第5次之间的差值:0xFF-0x94+0x18=0x83

出0入309汤圆

发表于 2011-1-22 00:35:46 | 显示全部楼层
回复【398楼】machao  
更容易说明问题的测试是采用16位定时器,调试中看汇编代码,看2次中断的间隔是否是你设定的中断间隔,在中断中任何一句指令上暂停都可以,加几个NOP都没有关系的,正确的应该测两次中断到同一个地方时的间隔是否是你设定的中断间隔。
-----------------------------------------------------------------------
不一定。中断的调用至少也得等待当前汇编指令执行完。由于指令执行时间不一致,会导致抖动。当然,不会造成CTC累积误差。
我在51(没有预分频)里的解决方法是在中断服务程序里根据计时器的值相对跳转到一个nop的序列里,离开这个序列的时候,这个误差就被补偿了。

出0入0汤圆

发表于 2011-1-22 00:36:03 | 显示全部楼层
"TCNT0+=250; "

that can be quite risky with this approach: because of latency, if TCNT0 has a value greater than 5, adding 250 to it can cause an immediate overflow and you will get the wrong interrupt interval - this is particularly true with low timer prescaler. and this is a case where hardware reload does have advantage over software reload, as I suggested a while back in this very thread.

try a number a little bit lower. if you think your latency is no more than 50 (cycles), anything less than 200 should work.

出0入0汤圆

 楼主| 发表于 2011-1-22 00:37:17 | 显示全部楼层
回复【397楼】zhxzhx 一丁
machao  
   millwood0 始终在这个问题上想不开,我和他也讨论过这个问题,我连用51都是尽量用自动装载,不行的话也要调整晶振是13,或16位的溢出满足定时要求,最次也要保证低8位要自动归零,然后尽快只调整高8位的计数值.
-----------------------------------------------------------------------

他可能是软件出身的,软件定时这样做是准确的,只要保证计数器加的过程为原子操作。硬件计数器做不到。
另外,他的确在软件方面有相当的功底,而这样的人也通常非常自信。但是我也已经解释的够清楚了。

出0入0汤圆

发表于 2011-1-22 00:39:14 | 显示全部楼层
饿了,困了,头疼,吃面,洗澡,睡觉,明天用TIM1来监测

出0入309汤圆

发表于 2011-1-22 00:41:58 | 显示全部楼层
回复【402楼】millwood0  
"tcnt0+=250; "

that can be quite risky with this approach: because of latency, if tcnt0 has a value greater than 5, adding 250 to it can cause an immediate overflow and you will get the wrong interrupt interval - this is particularly true with low timer prescaler. and this is a case where hardware reload does have advantage over software reload, as i suggested a while back in this very thread.
......
-----------------------------------------------------------------------

No, I've strictly tested the code. 251 will not work, but 250 does.
I use the largest possible value to make up for the f**king storage depth of my Tek oscilloscope.

出0入0汤圆

发表于 2011-1-22 00:46:40 | 显示全部楼层
"第1次和第2次之间的差值:0xFF-0x88+0x0C=0x83
第3次和第2次之间的差值:0x8E-0x0C=0x82
第4次和第3次之间的差值:0xFF-0x8E+0x12=0x83
第5次和第4次之间的差值:0x94-0x12=0x82
第6次和第5次之间的差值:0xFF-0x94+0x18=0x83 "

that doesn't make a lot of sense to me. as the offset is 0x80 (=-0x7f), the interval you get should be less than 0x80, not over it.

I will play with my hardware to see what I get.

出0入0汤圆

发表于 2011-1-22 00:48:13 | 显示全部楼层
"251 will not work, but 250 does. "

the latency seems to be 3 ticks before the 1st line in the isr is executed. so maybe 251 is pushing.

出0入0汤圆

发表于 2011-1-22 00:53:00 | 显示全部楼层
回复【406楼】millwood0
-----------------------------------------------------------------------

“that doesn't make a lot of sense to me. as the offset is 0x80 (=-0x7f), the interval you get should be less than 0x80, not over it. ”

Tim2 do nothing but count, I use AVR Dragon to do the hardware simulate, the same breakpoint, exactly the value in TCNT2, how can you explain this? Yes, it should be 0x80 only if your method is right, but this result prove that it is wrong.

出0入0汤圆

发表于 2011-1-22 00:54:54 | 显示全部楼层
回复【406楼】millwood0
-----------------------------------------------------------------------

Try to use a hardware simulator, not Proteus.

出0入0汤圆

 楼主| 发表于 2011-1-22 00:56:06 | 显示全部楼层
回复【401楼】iamseer

不一定。中断的调用至少也得等待当前汇编指令执行完。由于指令执行时间不一致,会导致抖动。当然,不会造成ctc累积误差。
我在51(没有预分频)里的解决方法是在中断服务程序里根据计时器的值相对跳转到一个nop的序列里,离开这个序列的时候,这个误差就被补偿了。
-----------------------------------------------------------------------
下面是16位计数器加128的汇编:

     0000 0005    TCNT1 += 128;
        IN   R30,0x2C          ====》把此时的TCNT1锁到16位的辅助寄存器中,读16位缓冲寄存器的低8位
        IN   R31,0x2C+1         ===》这里读16位缓冲寄存器的高8位,真正的TCNT1已经加1了
        SUBI R30,LOW(-128)
        SBCI R31,HIGH(-128)    =====》加128需要2条指令,此时TCNT1又加了2
        OUT  0x2C+1,R31        =====》写入16位缓冲寄存器高8位,实际的TCNT1又加了1
        OUT  0x2C,R30          ======》写入16位缓冲区低8位,同时将16位缓冲寄存器值打入TCNT1!至少差了4个CLK!!!
     0000 0006    #asm("nop")
        nop

你是硬件出身还是软件出身?

出0入309汤圆

发表于 2011-1-22 01:07:33 | 显示全部楼层
回复【410楼】machao  

-----------------------------------------------------------------------

可能我表达有误。我针对的是“2次中断的间隔”。Avr我没深入研究过这个问题。但是对于51这种低速机来说,问题很大。
响应中断至少也要将PC指针指向的代码执行完成,然后在转向中断向量表。
但是"PC指针指向的代码执行完成"的时间是不确定的,如果这是一条MUL AB这种4周期指令,那么中断请求发生时MUL到底执行到哪一步?也是不确定的。所以,中断会有最多3时钟的误差。

出0入0汤圆

 楼主| 发表于 2011-1-22 01:08:25 | 显示全部楼层
回复【405楼】iamseer
回复【402楼】millwood0   
"tcnt0+=250; "
that can be quite risky with this approach: because of latency, if tcnt0 has a value greater than 5, adding 250 to it can cause an immediate overflow and you will get the wrong interrupt interval - this is particularly true with low timer prescaler. and this is a case where hardware reload does have advantage over software reload, as i suggested a while back in......
-----------------------------------------------------------------------

如果是8位的话,250、251都是非常危险的,因为中断的间隔已经小与中断服务执行的时间了,中断响应和返回也本身也需要时间的,还是用小点的数,直接用16位的测试。

不要用软件模拟!

出0入0汤圆

 楼主| 发表于 2011-1-22 01:19:52 | 显示全部楼层
回复【411楼】iamseer

-----------------------------------------------------------------------
可能我表达有误。我针对的是“2次中断的间隔”。avr我没深入研究过这个问题。但是对于51这种低速机来说,问题很大。
响应中断至少也要将pc指针指向的代码执行完成,然后在转向中断向量表。
但是"pc指针指向的代码执行完成"的时间是不确定的,如果这是一条mul ab这种4周期指令,那么中断请求发生时mul到底执行到哪一步?也是不确定的。所以,中断会有最多3时钟的误差。

-----------------------------------------------------------------------
1。不管中断响应的过程是否每次相同,请你用16位计数器来验证。
2。看16位的计数器加一个数再回写需要几条汇编指令,不要看C代码。C看上去一句,成为汇编就是几条指令。
3。在你做加法的时候,硬件计数器也在自动加1,请彻底的明确明白,所以你的加法不是原子操作
4。不是原子操作这里就对精确定时产生影响。中断响应的影响是另外的因素,这个是无法估计的。

出0入309汤圆

发表于 2011-1-22 01:29:28 | 显示全部楼层
回复【413楼】machao  

-----------------------------------------------------------------------
呃。。。。
340楼我贴的汇编代码就是在说这个问题。
另外我411楼的内容是针对在未分频情况下利用定时器补偿“中断响应的影响”。而不是在说中断内如何操作TCNT0会如何。

出0入0汤圆

 楼主| 发表于 2011-1-22 01:38:29 | 显示全部楼层
回复【406楼】millwood0
"第1次和第2次之间的差值:0xff-0x88+0x0c=0x83
第3次和第2次之间的差值:0x8e-0x0c=0x82
第4次和第3次之间的差值:0xff-0x8e+0x12=0x83
第5次和第4次之间的差值:0x94-0x12=0x82
第6次和第5次之间的差值:0xff-0x94+0x18=0x83 "
that doesn't make a lot of sense to me. as the offset is 0x80 (=-0x7f), the interval you get should be less than 0x80, not over it.
i will play with my hardware to see what i get.

-----------------------------------------------------------------------

这个测试已经说明问题了,考虑1CLK为抖动,那么间隔多了2个CLK。

  ; 0000 0017 TCNT0 += 0x05;     TCNT0的正常值                           软件操作
  IN   R30,0x32          ;         0x80                                  读0x80                                 
  SUBI R30,-LOW(5)       ;         0x81                                    0x85
  OUT  0x32,R30          ;         0x82                                写入0x85

  当最后一条指令执行完成后,TCNT0为085,但正确的值应该是 0x87 = 0x82+5!
  这里少了2个,意味着计数器需要多计2个CLK,所以间隔多了2个CLK,绝对不会少的。

出0入0汤圆

 楼主| 发表于 2011-1-22 02:05:00 | 显示全部楼层
回复【414楼】iamseer
-----------------------------------------------------------------------
呃。。。。
340楼我贴的汇编代码就是在说这个问题。
另外我411楼的内容是针对在未分频情况下利用定时器补偿“中断响应的影响”。而不是在说中断内如何操作tcnt0会如何。

-----------------------------------------------------------------------
1。首先需要彻底的清楚,使用溢出中断的方式将影响定时的精度,这个是明确的。但millwood0还不认识到,认为TCNTO+=0xXX能行。

2。采用CTC模式对中断抖动有补偿作用的,只是它的补偿作用表现是在下一次。如果这次由于抖动使得中断间隔长了1个CLK,那么下次间隔就会少1个CLK。因为中断响应的抖动并不影响计数器硬件的自动计数过程。它只是影响软件执行过程。

3。另外解决中断抖动的办法还是利用CTC中断模式。在中断的第一句读计数器的值,然后根据需要选择执行不同几个NOP指令。因为CTC模式下,计数器永远不会受到任何的干扰,有一个clk就计一个CLK。不过这里还是有1个clk的不确定性。

出0入0汤圆

发表于 2011-1-22 02:35:01 | 显示全部楼层
回复【378楼】li900309

好吧,你要这样说话我也没办法

我只是提醒你做老师谦虚慎言也是美德你存心想吵架我没办法

你对 教授啊 博士学者之类的一直耿耿于怀,他们跟你做的就不是一种工作,科学和技术是不一样的。。。  

没有物理学没有半导体哪来的AVR?

说“中专”不是贬低你的水平,是说你教的课程是一门应用技术,本科生上和中专生都可以学,作为老师教书育人是没有区别的,

作为学生,大部分学生也是向中专生看齐的,现在的本科早就不是精英教育了

你去中专教书也能培养出色的人才,你能想象去中专教固体物理吗?

撤退看书去,我手下败将,高兴了?
-----------------------------------------------------------------------
作为旁人,说两句话:
这哥们有点那个
没有物理学没有半导体哪来的AVR?
那没有农民种田,也就没有你,那就没有半导体!
别给别人一种感觉:让人觉得你自己的专业就好,就是高人一等

出0入0汤圆

发表于 2011-1-22 08:24:48 | 显示全部楼层
收藏了慢慢看:)

果然如我所愿啊,又可以学到不少,谢谢各位啊:)

出0入0汤圆

发表于 2011-1-22 08:45:55 | 显示全部楼层
标记学习!

出0入0汤圆

发表于 2011-1-22 09:50:29 | 显示全部楼层
回复【312楼】snoopyzz  
-----------------------------------------------------------------------

回复【313楼】machao  
-----------------------------------------------------------------------

马老师是否是因为看到我下面这段的代码感到没价值看了吗??马老师不是曾介绍过PT的吗?
PT_DELAY_TICK是借用ProtoThreads的思想,具体定义在240L的PT.h中,利用固定主循环周期,switch,case,return做阻塞,
以下代码就算没注释,只要知道是8x8矩阵LED,有C基础的应该都清楚知道下面的代码想做什么.
曾几何时,我觉得对于编程而言,省代码和RAM,以最高效率写代码等等相关优化的技巧很重要,并慢慢在成长积累了很多优化相关奇淫巧技,
但渐渐的,如今MCU的MIPS,flash,ram都不是大问题,stm8s103(2.2RMB含税价,16MHz,8K flash,1K ram足以满足我项目中大部分应用)
而且是这次的题目用的是M16,用不完也是浪费,清晰化程序结构,模块化功能层次,代码的扩展性等反而显得更为重要
所以我才做了这样的代码

ps.若是比代码小,写出比马老师更小些的也不是什么难事,精简代码,提高程序效率,是我一年前的强项,嘿嘿
=================================
以下代码完整版 在240L,
void Task_DoDraw(void)
{
    static u8 n;
    PT_INIT()
    PT_INIT_DELAY(u16)
    PT_BEGIN()
        Led_Clear();
        Led_DrawPoint(3,3);
        Led_DrawPoint(3,4);
        Led_DrawPoint(4,3);
        Led_DrawPoint(4,4);
        //
        Task.Tick = MS(200);
        for(;;)
        {
            for(n=0;n<8;n++)
            {
                Led_DrawPoint(n,0);
                PT_DELAY_TICK(Task.Tick);
                Led_ClearPoint(n,0);
            }
            for(n=0;n<8;n++)
            {
                Led_DrawPoint(7,n);
                PT_DELAY_TICK(Task.Tick);
                Led_ClearPoint(7,n);
            }
            for(n=7;(s8)n>=0;n--)
            {
                Led_DrawPoint(n,7);
                PT_DELAY_TICK(Task.Tick);
                Led_ClearPoint(n,7);
            }
            for(n=7;(s8)n>=0;n--)
            {
                Led_DrawPoint(0,n);
                PT_DELAY_TICK(Task.Tick);
                Led_ClearPoint(0,n);
            }
        }
    PT_END()
}

出0入0汤圆

发表于 2011-1-22 13:04:49 | 显示全部楼层
对这题兴趣不大,这是我的拙作,ATMEGA16:

(原文件名:ourdev_557287.jpg)
所花时间,半天,主要时间是倒腾素材,呵呵。
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4057879

出0入0汤圆

 楼主| 发表于 2011-1-22 13:28:23 | 显示全部楼层
回复【421楼】sharpufo 风生水起月皎白
对这题兴趣不大,这是我的拙作,atmega16:


(原文件名:ourdev_557287.jpg)
引用图片
所花时间,半天,主要时间是倒腾素材,呵呵。
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4057879
-----------------------------------------------------------------------

咳,真不想多说什么,有位朋友还是说了许多实在的话,现在的学校很多都是神马学校 。。。
我有几块这样的等离子屏(还有3色的)已经睡了几年了。没有学生想玩

出0入0汤圆

 楼主| 发表于 2011-1-22 13:34:41 | 显示全部楼层
回复【420楼】snoopyzz
-----------------------------------------------------------------------
马老师是否是因为看到我下面这段的代码感到没价值看了吗??马老师不是曾介绍过pt的吗?
pt_delay_tick是借用protothreads的思想,具体定义在240l的pt.h中,利用固定主循环周期,switch,case,return做阻塞,
以下代码就算没注释,只要知道是8x8矩阵led,有c基础的应该都清楚知道下面的代码想做什么.
曾几何时,我觉得对于编程而言,省代码和ram,以最高效率写代码等等相关优化的技巧很重......
-----------------------------------------------------------------------

这个内容在此贴继续讨论不适合,属于更深层次的问题(可以到达硕士,甚至博士级讨论研究水平)。
我知道你的代码和思想,等我把手头的工作完成然后专门开个题,欢迎你能积极参与,大家交流。

出0入0汤圆

发表于 2011-1-22 13:53:19 | 显示全部楼层
回复【422楼】machao
回复【421楼】sharpufo 风生水起月皎白
对这题兴趣不大,这是我的拙作,atmega16:  

  
(原文件名:ourdev_557287.jpg)

&lt;a class=tt16 onclick="fnquickimagequote(this,'files_35/ourdev_612818xl0gw0.jpg','原文件名:ourdev_557287.jpg')" href="###"&gt;引用图片</a>
所花时间,半天,主要时间是倒腾素材,呵呵。  
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=4057879
---------------------------------------......
-----------------------------------------------------------------------

马老师您好,这不是等离子屏,是普通的LED双色屏. 595驱动.

出0入0汤圆

发表于 2011-1-22 14:27:19 | 显示全部楼层
回复【157楼】machao
-----------------------------------------------------------------------

if if if if==》if  else if  else if  else。

出0入309汤圆

发表于 2011-1-22 18:35:41 | 显示全部楼层
回复【416楼】machao  
3。另外解决中断抖动的办法还是利用CTC中断模式。在中断的第一句读计数器的值,然后根据需要选择执行不同几个NOP指令。因为CTC模式下,计数器永远不会受到任何的干扰,有一个clk就计一个CLK。不过这里还是有1个clk的不确定性。

-----------------------------------------------------------------------

今天看EE476的Video Generation代码,里面有这样一句:
//This is the sync generator and raster generator. It MUST be entered from
//sleep mode to get accurate timing of the sync pulses
在主循环里程序进入IDLE,这种方法的确可以做到中断响应一丝不差。

出0入0汤圆

发表于 2011-1-22 21:26:19 | 显示全部楼层
这贴得顶一顶...

出0入0汤圆

发表于 2011-1-23 02:00:10 | 显示全部楼层
学校讨论有学士硕士博士教授专家长江学者的区别,俺在社会上混久了,对头衔麻木了,只对孔方兄敏感了

顺便学习一下基本知识,才几十个的关键字的C,咋就变出这么多古怪的名堂

一片森林和一朵鲜花的区别,鸡和蛋的辩论

出0入0汤圆

发表于 2011-1-23 10:28:27 | 显示全部楼层
很有意思!

出0入0汤圆

发表于 2011-1-27 09:39:52 | 显示全部楼层
个人喜欢240Lsnoopyzz的编程思想及代码风格。。。。

出0入0汤圆

发表于 2011-1-27 09:53:41 | 显示全部楼层

(原文件名:截图1296093051.jpg)


(原文件名:截图1296093071.jpg)

出0入0汤圆

发表于 2011-1-27 10:46:19 | 显示全部楼层
to 马朝:

看不起北大有些人是正常的,看不起北大的有些方面也是正常的,但看不起整个北大乃至北大所有人,就过火了

北大是没设计出过自己的商业 CPU,但钱敏平的团队加入龙芯后,龙芯很快就被 BSD 阵营承认,这也是事实

其实真要说起来,北大应该也是 PRC 少有的几个能公开接受并宽容持不同_政见者的地方了(不仅仅说大学),这点上,我相信就算你马朝所在的学校也绝对做不到,因为你毕竟不是校长,你也更不可能撑得住整个统治集团的压力

大学这玩意,技术永远是次要的,人文环境和学术精神才是主要的——因为不管你在学校里学到怎样的技术,出门后都是不够用甚至不够看的

甚至更诛心一点的说,如果一个人在整个学校环境里不能接受到正确的人文环境熏陶,这样的人,出去以后,技术越高,对社会对人类造成的危害越大——北邮那一帮子做 GFW 的 WBD 就充分的证明了这一点

出0入0汤圆

发表于 2011-1-27 10:56:06 | 显示全部楼层
另外不得不说,从头到尾,楼主你炫耀的只是一个合格电子工程师应该具备的小技巧

你可以依此证明现在的许多大学生很渣、接受的教育也很渣,但若只以这点技巧来衡量,我也只能说,现在大学的副教授职称也确实是随便评的

用有的技巧多,你可以成为工程师、高级工程师、超级工程师、究级工程师,但这不是成为一个教授的前提

在 PRC 现行环境下,教授(非叫兽)应该做什么?不是往别人脑子里灌输一堆肯定很好用的小窍门,而是教会大家自由思考,教会大家打破十几年政治挂帅教育带来的僵化思维模式

出0入0汤圆

发表于 2011-1-27 11:49:52 | 显示全部楼层
回复【432楼】waitingconfirm  
to 马朝:
看不起北大有些人是正常的,看不起北大的有些方面也是正常的,但看不起整个北大乃至北大所有人,就过火了
北大是没设计出过自己的商业 cpu,但钱敏平的团队加入龙芯后,龙芯很快就被 bsd 阵营承认,这也是事实
其实真要说起来,北大应该也是 prc 少有的几个能公开接受并宽容持不同_政见者的地方了(不仅仅说大学),这点上,我相信就算你马朝所在的学校也绝对做不到,因为你毕竟不是校长,你也更不可能撑得住整个统治集团的压力
大学这玩意,技术永远是次要的,人文环境和学术精神才是主要的——因为不管你在学校里学到怎样的技术,出门后都是不够用甚至不够看的
甚至更诛心一点的说,如果一个人在整个学校环境里不能接受到正确的人文环境熏陶,这样的人,出去以后,技术越高,对社会对人类造成的危害越大——北邮那一帮子做 gfw 的 wbd 就充分的证明了这一点
-----------------------------------------------------------------------

支持!大学要培养的不是社会机器里的一个螺丝,而是一个人。

出0入0汤圆

发表于 2011-1-27 15:37:31 | 显示全部楼层
讨论很精彩,收藏之

出0入0汤圆

发表于 2011-1-27 17:56:05 | 显示全部楼层
自学51的c
没有用过avr
用的STC89c51
代码不是很规范 没有用定时器 各位大神见笑了
#include <reg51.h>
#include <intrins.h>
void delay(unsigned char a)
{
        for(a;a>1;a--)
        {}
        return;
}
void Display_P1(unsigned char cn)
{
        P1=cn;
}
void Display_P0(unsigned char cn)
{       

        P0=cn;
}
void main()
{       
        unsigned char b0,b1,i,x;
        unsigned char n;
        n=0;
        b0=0xFE;
        b1=0xFE;
        i=0;
        x=0;
        do
                {
                                P0=0xE7;
                                P1=0xE7;
                                delay(250);
                                n++;
                                Display_P1(b1);
                                Display_P0(b0);
                                delay(250);
                                if(n==200)
                                        {
                                                switch(i)
                                                {
                                                        case 0:
                                                        {
                                                                b1=_crol_(b1,1);
                                                                x++;
                                                                if(x==7)
                                                                {
                                                                        x=0;
                                                                        i++;
                                                                 }
                                                                 break;
                                                         }
                                                         case 1:
                                                         {
                                                                 b0=_crol_(b0,1);
                                                                x++;
                                                                if(x==7)
                                                                {
                                                                        x=0;
                                                                        i++;
                                                                 }
                                                                 break;
                                                         }
                                                         case 2:
                                                         {
                                                                 b1=_cror_(b1,1);
                                                                x++;
                                                                if(x==7)
                                                                {
                                                                        x=0;
                                                                        i++;
                                                                }
                                                                break;
                                                         }
                                                         case 3:
                                                         {
                                                                 b0=_cror_(b0,1);
                                                                x++;
                                                                if(x==7)
                                                                {
                                                                        x=0;
                                                                        i=0;
                                                                }
                                                                break;
                                                         }          
                                                }
                                                n=0;
                                         }               
                                }
        while(1);
}

出0入0汤圆

发表于 2011-2-12 18:47:25 | 显示全部楼层
从北大未名那里发现 本帖的链接 ======呵呵 =====话说不进教育网连北大未名都访问不了 ,,,感谢国家啊我操 ,,,

出0入0汤圆

发表于 2011-2-12 18:49:20 | 显示全部楼层
继续欢迎 塔里埃尔 等pku的高人们来砸场子,,,好好教育教育广大身处残酷剥削和压榨的各大小公司的it民工 ,,,嘿嘿
ps  基本泡cjdby了 ,,,觉得中国的精英都tmd五毛了,还有就是觉得体制内的人真的犯了不作为罪!你们等着被饥饿的贱民暴民们煮着吃吧

出0入0汤圆

发表于 2011-3-20 15:44:14 | 显示全部楼层
马老师等人为单片机的普及做出卓越贡献,值得尊敬!
还有些人,也不知道到底有没为社会做出的啥,只会没事太饱乱拍砖头,(#‵′)凸.......

出0入0汤圆

发表于 2011-5-27 10:23:50 | 显示全部楼层
标记!

出0入0汤圆

发表于 2011-5-30 17:20:54 | 显示全部楼层
精彩ing

出0入0汤圆

发表于 2011-5-30 18:59:50 | 显示全部楼层
我只会玩51,写了一个不知能不能用,应该问题不大。键盘检查没做,没什么大难度。另外有些51无法直接驱动LED,电流不够,暂不考虑,只看时序。
坐标定义如下:
//8
//7
//6
//5
//4
//3
//2
//1 2 3 4 5 6 7 8
//坐标在第一象限,不含0,0点
//
//
//
unsigned char TimerCounter=0;
unsigned char LocateX=1,LocateY=8;

void Dot(unsigned char x,unsigned char y)
{
        unsigned char X_tmp=0x80,Y_tmp=0x7f;        //初始化为坐标1,1,P0为正P2为负
        X_tmp=_cror_(X_tmp,x);                        //向右移动X轴
        Y_tmp=_cror_(Y_tmp,y);                        //向上移动Y轴

        X_tmp&=0x18;                                //点亮中间的4个点
        X_tmp&=0xe7;                                //点亮中间的4个点

        P0=X_tmp;
        P2=Y_tmp;
}
void Move()
{
        if(LocateY==8)                //顶部
                {
                        if(LocateX<8)        //且未到达最右边
                                LocateX++;
                }
        else if(LocateY==1)                //底部
                {
                        if(LocateX>1)        //且未到达最左边
                                LocateX--;
                }
        else if(LocateX==8)                //右边
                {
                        if(LocateY>1)        //且未到达底部
                                LocateY--;
                }
        else if(LocateX==1)                //左边
                {
                        if(LocateY<8)        //且未到达顶部
                                LocateY++;
                }

        Dot(LocateX,LocateY);
}

void Timer0() interrupt 1
{
        TH0=0x7d;
        TL0=0xca;
        TimerCounter++;
        if(TimerCounter==2)
                {
                        TimerCounter=0;
                        Move();
                }
}

void main()
{
        TMOD=0x01;
        TH0=0x7d;        //4M的晶振51恰好定时不了200mS,我晕
        TL0=0xca;
        TR0=1;
        EA=1;
}

出0入0汤圆

发表于 2011-5-30 20:18:21 | 显示全部楼层
看了两个多小时的评论,我喜欢看评论

出0入0汤圆

发表于 2011-6-26 22:35:03 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-7-24 23:00:02 | 显示全部楼层
中国社会主义初级阶段的基本问题其实还是农民问题

出0入0汤圆

发表于 2011-8-18 12:39:44 | 显示全部楼层
唉,中国人即使是讨论任何问题都会针对本人进行攻击,恐怕这是通病吧。
我提出自己的想法:
1.定时采用CTC模式,精确定时(相对普通模式)
2.中断采用奇偶方式,中断函数扫描灯,并同时作时间计时(解决0.2s间隔问题):奇数时亮四周灯,灭中间灯;偶数时采用亮中间灯,灭四周灯

出0入0汤圆

发表于 2011-8-18 12:54:13 | 显示全部楼层
这个帖子很精彩啊,要顶。

出0入0汤圆

发表于 2011-8-18 13:02:20 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-12-28 08:28:16 | 显示全部楼层
马老师  150多楼的那个题目 太难了  考试用的题目么?  那肯定得挂科啊。怎么也得让得60分啊。

教学教学   教如何规范写程序  教基础可以学深层次的  但是一定要考基础的

出0入0汤圆

发表于 2012-1-3 21:58:54 | 显示全部楼层
很好的帖子啊

出0入0汤圆

发表于 2012-1-4 19:24:47 | 显示全部楼层
受教了,谢谢马老师~

出0入0汤圆

发表于 2012-1-4 21:52:26 | 显示全部楼层
关于led显示的驱动,中断实现,讨论精彩,言辞犀利,重点可关注184  188 223 235 281 313 318 321 431楼

出0入0汤圆

发表于 2012-1-4 22:43:34 | 显示全部楼层
回复【432楼】waitingconfirm  
to 马朝:
看不起北大有些人是正常的,看不起北大的有些方面也是正常的,但看不起整个北大乃至北大所有人,就过火了
北大是没设计出过自己的商业 cpu,但钱敏平的团队加入龙芯后,龙芯很快就被 bsd 阵营承认,这也是事实
其实真要说起来,北大应该也是 prc 少有的几个能公开接受并宽容持不同_政见者的地方了(不仅仅说大学),这点上,我相信就算你马朝所在的学校也绝对做不到,因为你毕竟不是校长,你也更不可能撑得住整个统治集团的压力
大学这玩意,技术永远是次要的,人文环境和学术精神才是主要的——因为不管你在学校里学到怎样的技术,出门后都是不够用甚至不够看的
甚至更诛心一点的说,如果一个人在整个学校环境里不能接受到正确的人文环境熏陶,这样的人,出去以后,技术越高,对社会对人类造成的危害越大——北邮那一帮子做 gfw 的 wbd 就充分的证明了这一点
-----------------------------------------------------------------------

有道理
头像被屏蔽

出0入0汤圆

发表于 2012-1-17 10:29:23 | 显示全部楼层
很经典,学习了这个就可以做一个点阵显示了!!

出0入0汤圆

发表于 2012-5-17 16:26:00 | 显示全部楼层
话说,用单片机的IO直接驱动点阵LED成本还是挺低的。当然用单片机的IO直接驱动LED应该会有显示不均匀的问题(横流驱动),对于学生阶段应该足够了,这样容易理解;个人理解程序的效率和代码量,这两个问题有时候是没办法评估的。

出0入0汤圆

发表于 2012-8-22 10:17:56 | 显示全部楼层
看完考卷我感觉自己可以去死了

出0入0汤圆

发表于 2012-8-23 01:55:24 | 显示全部楼层
实现该功能的程序源代码如下:


I think I can write a piece of code that's materially better than this.

Let me point out a few areas where you can improve upon.

1) overall, the code is not well documented. there are implicit assumptions on how the pins are arranged. yet that's undocumented. the code is poorly commented in general.

2) the code is not written for portability / reusability. for example, if you were to move the code to a different chip, you need to materially rewrite the code; or to move the ports around.

3) "#include <mega16.h>": you want to use a generic header file that directs you to the right header file for your processor, not to invoke that specific header file.

4) "char dis_buff[8] = {0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00};": making is in rom / flash helps. and this is where a const modifier should be used.

5) "char j=0,line=0,point;": if you could specify "unsigned", specify "unsigned".

6) "bit t_xxms_ok;": if you could avoid using a non-standard C data type, you should.

7) "void led8x8(void) {": a more generic version of this would use a pointer to indicate where the image is.

8) "   PORTC = ~(1<<i);" consider using a mask.

...

this kind of code will certainly fail you in any 1st round interview for an entry level programming job.

出0入0汤圆

发表于 2012-9-27 16:01:56 | 显示全部楼层
学习学习!!!

出0入0汤圆

发表于 2012-12-10 12:24:43 | 显示全部楼层
学习了,看完后收益匪浅

出0入0汤圆

发表于 2013-3-28 20:17:57 | 显示全部楼层
看完了感觉。。。。。思路很好,。。虽然AVR我只懂一点点,受益匪浅。。。。

出0入0汤圆

发表于 2013-7-15 10:22:38 | 显示全部楼层
我也买了马老师的书,第一眼,就觉得A口输出的数据根据行列来变换不怎么好弄,先用二维数组来实现。

*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
?Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version : 1.0
Date    : 2013-7-15
Author  : JianZhou
Company : LieMing
Comments:


Chip type           : ATmega16
Program type        : Application
Clock frequency     : 4.000000 MHz
Memory model        : Small
External RAM size   : 0
Data Stack size     : 256
*****************************************************/

#include <mega16.h>

flash unsigned char led_7[28][8]={{0x80,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
                                  {0x40,0x00,0x00,0x18,0x18,0x00,0x00,0x00},  
                                  {0x20,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
                                  {0x10,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
                                  {0x08,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
                                  {0x04,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
                                  {0x02,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
                                  {0x01,0x00,0x00,0x18,0x18,0x00,0x00,0x00},
                                  {0x00,0x01,0x00,0x18,0x18,0x00,0x00,0x00},
                                  {0x00,0x00,0x01,0x18,0x18,0x00,0x00,0x00},
                                  {0x00,0x00,0x00,0x19,0x18,0x00,0x00,0x00},
                                  {0x00,0x00,0x00,0x18,0x19,0x00,0x00,0x00},
                                  {0x00,0x00,0x00,0x18,0x18,0x01,0x00,0x00},
                                  {0x00,0x00,0x00,0x18,0x18,0x00,0x01,0x00},
                                  {0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x01},
                                  {0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x02},
                                  {0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x04},
                                  {0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x08},
                                  {0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x10},
                                  {0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x20},
                                  {0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x40},
                                  {0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x80},
                                  {0x00,0x00,0x00,0x18,0x18,0x00,0x80,0x00},
                                  {0x00,0x00,0x00,0x18,0x18,0x80,0x00,0x00},
                                  {0x00,0x00,0x00,0x18,0x98,0x00,0x00,0x00},
                                  {0x00,0x00,0x00,0x98,0x18,0x00,0x00,0x00},
                                  {0x00,0x00,0x80,0x18,0x18,0x00,0x00,0x00},
                                  {0x00,0x80,0x00,0x18,0x18,0x00,0x00,0x00}};

flash unsigned char position[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
unsigned char col=0;
unsigned char row=0;
unsigned char time_counter=0;

bit time_200ms_ok=0;

void display(void)
{
    PORTC=0xff;
    PORTA=led_7[col][row];
    PORTC=position[row];
    if (++row>=8) row=0;
   
};




// Timer 0 output compare interrupt service routine
interrupt [TIM0_COMP] void timer0_comp_isr(void)
{
    display();
    if (++time_counter>=100)
    {
        time_counter=0;
        time_200ms_ok=1;
    }

}


void main(void)
{

// Input/Output Ports initialization
// Port A initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTA=0x00;
DDRA=0xFF;



// Port C initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=1 State6=1 State5=1 State4=1 State3=1 State2=1 State1=1 State0=1
PORTC=0xFF;
DDRC=0xFF;



// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 62.500 kHz
// Mode: CTC top=OCR0
// OC0 output: Disconnected
TCCR0=0x0B;
TCNT0=0x00;
OCR0=0x7c;             //OCR0=0x7C (124+1)/62.5k=2ms

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x02;



// Global enable interrupts
#asm("sei")

while (1)
      {
        if (time_200ms_ok)
        {
            if (++col>=28) col=0;
            time_200ms_ok=0;
        }
        
                  

      };
}

出0入0汤圆

发表于 2013-7-15 20:33:22 | 显示全部楼层
晚上回家,再读大家的帖子,这里挺好的。读了以后有很多的收获。马老师的程序确实比我早上1个小时的二维数组模式精妙。28个状态,PC0-PC7依次扫描。

void led8x8(void) {
    static char i = 0;
    PORTC = 0xff;
    PORTA = dis_buff;
    if (i = = line)  PORTA = dis_buff | point;
    PORTC = ~(1<<i);
    if(++i>7) i = 0;
}

这里有错误,dis_buff应为dis_buff[i]  我也觉得奇怪了,定义了dis_buff[],dis_buff是数组的首地址,PORTA = dis_buff; 地址怎么能赋值给数据能。

出0入0汤圆

发表于 2013-7-15 20:42:42 | 显示全部楼层
我加了按键的功能,PD.0接按键  实现了功能,按键用状态机的思想,参考马老师的程序。实现了按键改延时时间的功能。

/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.4 Standard
Automatic Program Generator
?Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project :
Version : V1.1
Date    : 2013-7-15
Author  : JianZhou
Company :
Comments:


Chip type           : ATmega16
Program type        : Application
Clock frequency     : 4.000000 MHz
Memory model        : Small
External RAM size   : 0
Data Stack size     : 256
*****************************************************/

#include <mega16.h>

char dis_buff[8] = {0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00};
char j=0,line=0,point;
int time_count;
char key_stime_counter;
int t_counter=100;
char time_plus;

bit t_xxms_ok,key_stime_ok;

void led8x8(void)
{
    static char i = 0;
    PORTC = 0xff;
    PORTA = dis_buff;
    if (i == line)  PORTA = dis_buff| point;
    PORTC = ~(1<<i);
    if(++i>7) i = 0;
}

#define key_input PIND.0
#define key_state_0 0
#define key_state_1 1
#define key_state_2 2

unsigned char read_key(void)
{
    static unsigned char key_state=0;
    unsigned char key_press,key_return=0;
   
    key_press=key_input;
   
    switch(key_state)
    {
        case key_state_0:
            if (!key_press) key_state=key_state_1;
            break;
        case key_state_1:
            if (!key_press)
                {
                    key_return=1;
                    key_state=key_state_2;
                }
            else
                key_state=key_state_0;
            break;
        case key_state_2:
            if (key_press) key_state=key_state_0;
            break;
       }
       return key_return;   
}
// Timer 0 output compare interrupt service routine
interrupt [TIM0_COMP] void timer0_comp_isr(void)
{
    led8x8();
    if (++key_stime_counter>=5)
    {
        key_stime_counter=0;
        key_stime_ok=1;
    }
   
    if(++time_count >= t_counter)
    {
               
        time_count = 0;
        t_xxms_ok = 1;
    }

}

// Declare your global variables here

void main(void)
{

// Input/Output Ports initialization
// Port A initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTA=0x00;
DDRA=0xFF;



// Port C initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=1 State6=1 State5=1 State4=1 State3=1 State2=1 State1=1 State0=1
PORTC=0xFF;
DDRC=0xFF;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T

DDRD=0x00;




TCCR0=0x0B;
TCNT0=0x00;
OCR0=0x7C;


// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x02;


// Global enable interrupts
#asm("sei")

while (1)
      {
      
       if (key_stime_ok)
       {
            key_stime_ok=0;
            if (read_key())
            {
                t_counter +=t_counter;
                if (++time_plus>=5)
                {
                    t_counter=100;
                    time_plus=0;
                }
            }
       }           
     
        
      if(t_xxms_ok)
        {           t_xxms_ok = 0;
            
            if (j<8)
            {   line = 0; point = 0x80>>j;}
            if (j>=8 && j<14)
            {   line++; point = 0x01;}
            if(j>=14 && j< 22)
            {   line = 7; point = 0x01<<(j-14);}
            if (j>=22 && j< 28)
            {   line-- ; point = 0x80;}
            
            if(++j > 27) j = 0;
        }
    }

     
}

出0入0汤圆

发表于 2013-7-15 20:57:42 | 显示全部楼层
原来如此,是电脑的问题,我CVAVR粘帖的 disbuff[i]自动变成了dis_buff  

            if (j<8)
            {   line = 0; point = 0x80>>j;}
            if (j>=8 && j<14)
            {   line++; point = 0x01;}
            if(j>=14 && j< 22)
            {   line = 7; point = 0x01<<(j-14);}
            if (j>=22 && j< 28)
            {   line-- ; point = 0x80;}
            
            if(++j > 27) j = 0;

分析每个状态,PA口就输出了我早上做的二维数组的数据,精妙。

出0入0汤圆

发表于 2013-7-16 06:16:38 | 显示全部楼层
今天起来再测试按键,总感觉时间间隔不对,原来是t_counter+=t_counter;有误,应为t_counter+=100;再下载,对了。

出0入0汤圆

发表于 2013-8-1 01:34:08 | 显示全部楼层
读帖过瘾

出0入0汤圆

发表于 2013-8-1 09:48:30 | 显示全部楼层
可以拿回来做做

出0入0汤圆

发表于 2013-8-9 01:54:27 | 显示全部楼层
我晕  看了两个小时  终于看完第一遍了  值得关注  马老师好样的  这个脾气我喜欢  这样讨论才激烈  不过要是都放在主题上就好了

出0入0汤圆

发表于 2013-8-12 11:40:46 | 显示全部楼层
看到一半 有时间继续看

出0入0汤圆

发表于 2013-9-4 17:13:53 | 显示全部楼层
受教了                .

出0入0汤圆

发表于 2013-11-11 22:18:02 | 显示全部楼层
贴子很好,喜欢马老师风格

出0入0汤圆

发表于 2021-11-2 20:21:05 | 显示全部楼层
LED旋转未实现,只写了个main loop,回复以待老师审核


  1. void main() {
  2.     // var
  3.     char tick_flag;
  4.     char gap_cnt, gap_max;
  5.     char key_bak, key_bak_dly, key_cnt;
  6.     // init
  7.     tick_flag = 0;
  8.     gap_cnt = 0;
  9.     gap_max = 0;
  10.     key_bak = 0;
  11.     key_bak_dly = 0;
  12.     key_cnt = 0;
  13.     // loop
  14.     if(tick_flag) {
  15.         //-------------------------------------------------------------------
  16.         // init
  17.         //-------------------------------------------------------------------
  18.         tick_flag = 0;
  19.         //-------------------------------------------------------------------
  20.         // key proc
  21.         //-------------------------------------------------------------------
  22.         if ((key_bak&1) != key_in) { // key state change
  23.             key_cnt = key_cnt + 1;
  24.             if (key_cnt == 2) { // 400ms
  25.                 key_bak = key_in;
  26.                 key_cnt = 0;
  27.             }
  28.         }
  29.         else {
  30.             key_cnt = 0;
  31.         }
  32.         if (key_bak == 1 && key_bak_dly == 0) { // when key release
  33.             if (gap_max == 4) // more than 1s
  34.                 gap_max = 0;
  35.             else
  36.                 gap_max = gap_max + 2; // add 0.4s
  37.         }
  38.         key_bak_dly = key_bak; // dly
  39.         //-------------------------------------------------------------------
  40.         // led proc
  41.         //-------------------------------------------------------------------
  42.         if(gap_cnt >= gap_max) { // using >=, incase gap_max change
  43.             rotate_led();
  44.             gap_cnt = 0;
  45.         }
  46.         else {
  47.             gap_cnt = gap_cnt + 1;
  48.         }
  49.     }

  50. }
复制代码
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 10:04

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表