amoBBS 阿莫电子论坛

 找回密码
 注册
搜索
bottom↓
楼主: machao

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

[复制链接]
发表于 2011-1-20 02:44:50 | 显示全部楼层
【298楼】 machao

我没生气。


这个代码只是针对这个题目顺手写的,以前都没这么写过的,在看题的时候分析了下,发现只要扫三行,

剩下五行都是在扫空,所以代码就以扫三行的思路写下去了。

这个扫三行只对这个题目有效,正常还是得老老实实扫8行的。

这个代码可能占FLASH比较多点,但效率还是有的,一般专用程序会比通用程序效率高点。

由于时间原因,这个程序还没写到最简,可以再优化。
发表于 2011-1-20 03:12:54 | 显示全部楼层
【299楼】 millwood0

我是英盲,用软件翻译了下...

你的意思是不是说用正常的8次扫描,然后判断各行是否有显示内容,如果没有就跳过这行?


是个好方法啊,编程难度降低了好多,而且扫描次数大大减少,如果用在这个例子里扫描次数比我的3*8还要少。
发表于 2011-1-20 05:07:41 | 显示全部楼层
"你的意思是不是说用正常的8次扫描,然后判断各行是否有显示内容,如果没有就跳过这行? "

yes. However, there are issues with this approach:

1) it will be LESS efficient if you are displaying a full picture (aka no empty columns) as you are testing every column, sometimes unnecessarily;

2) the time to display all columns of a picture varies. As a result, the brightness varies, unless you utilize constant current drive.

in my view, it is more pain than gain.
发表于 2011-1-20 09:05:38 | 显示全部楼层
回复【298楼】machao  
-----------------------------------------------------------------------

还是烦请马老师帮看下240L的代码,给些意建,先谢了~
发表于 2011-1-20 09:22:40 | 显示全部楼层
回复【298楼】machao  
-----------------------------------------------------------------------

扫的行数少亮度可以有实实在在的提升。
发表于 2011-1-20 10:02:57 | 显示全部楼层
回复【285楼】machao  
-----------------------------------------------------------------------
在187楼是我没写清楚,187楼那个压缩包里是才是完整的代码。
里面有通用键盘驱动,系统节拍,通用LED阵列驱动等,是一个完整的平台。不过说实话那东西效率实在太蛋疼,编译出来M16代码空间一下子就用掉了15%,编译器是ICCAVR。

话说我就是看了马老师的书才入门的,在书店连续蹲了好几天哈哈。
发表于 2011-1-20 10:12:31 | 显示全部楼层
回复【283楼】machao
-----------------------------------------------------------------------

关于中断中的调用你说的对,我在188楼已经做了解释,我自己设计产品是放在主程序中调用的,中断中使用标志位。由于楼盖的太高了,你没注意到。
确实楼盖高了,没有注意到,马老师的开发板设计的很不错,下学期我也到学校做嵌入式教师了。希望能说服学校采用马老师设计的开发板。
发表于 2011-1-20 10:34:36 | 显示全部楼层
马老师好!

看了上面的讨论让我收获很多。之前我写的其实就是类似于上面的思路。不过我的可能更极端一些:我是直接显示外围一个点+中间四个点。

其实我也是有把层次分开的想法的,只是马老师对8*8点阵的驱动是8行扫描,我对它的驱动是显示一个点+显示中间四个点。
马老师的缓存是保存的整个点阵的信息,我的缓存保存的是那一个点的坐标。

虽然这样的程序没有什么通用性,但是就题论题的话显示的效率应该是比扫描8行的方法高一些吧。

当然我用了Delay这样的函数,只是之前没试过中断的方法,仓促之间就只好用了,如果时间在充裕一些我想我是能够改进的。
另外由于缺乏经验,程序肯定也是漏洞百出,还有很多可以改进的地方,望老师见谅


今天下午又在之前写的基础上简化了一下,有些地方做了改进,代码如下:


#include <intrins.h>
#include<STC12C5A.h>   

int x=0x80;
int y=0x80;       
int count=0;
int count2=4;
int dotplace=0;
bit disinf=0;

void Disp()
{
    if(disinf)
    {P2=x;P3=~y;}
    else
    {P2=0x18;P3=~0x18;}
}

void main()
{
    TMOD=0x01;
    TL0=0xE5;
    TH0=0xBE;
    TR0=1;
    ET0=1;
    EA=1;
    while(1)
    {Disp();}
}

void tm0() interrupt 1 using 1
{
    TL0=0xE5;
    TH0=0xBE;
    disinf=~disinf;
    if(count++==count2)
    {
        count=0;
        switch (dotplace)
        {
            case 0: if(x!=2)x>>=1;
                    else x=1,dotplace=1;break;
            case 1: if(y!=2)y>>=1;
                    else y=1,dotplace=2;break;
            case 2: if(x!=0x40)x<<=1;
                    else x=0x80,dotplace=3;break;
            case 3: if(y!=0x40)y<<=1;
                    else y=0x80,dotplace=0;break;
        }
    }
}
发表于 2011-1-20 11:28:49 | 显示全部楼层
我来挑战下,自认为更简单。不会用CVAVR,用的是ICC6.31A,芯片用的M8。
核心内容以下:
unsigned char Dtime200ms;
unsigned char LightLen,PowerLen;

unsigned char LightTab[28][6]={
        //移动的灯        固定的左2个        固定的右2个
        0x80,~0x01,        0x10,~0x18,        0x08,~0x18,
        0x40,~0x01,        0x10,~0x18,        0x08,~0x18,
        0x20,~0x01,        0x10,~0x18,        0x08,~0x18,
        0x10,~0x01,        0x10,~0x18,        0x08,~0x18,
        0x08,~0x01,        0x10,~0x18,        0x08,~0x18,
        0x04,~0x01,        0x10,~0x18,        0x08,~0x18,
        0x02,~0x01,        0x10,~0x18,        0x08,~0x18,
        0x01,~0x01,        0x10,~0x18,        0x08,~0x18,

        0x01,~0x02,        0x10,~0x18,        0x08,~0x18,
        0x01,~0x04,        0x10,~0x18,        0x08,~0x18,
        0x01,~0x08,        0x10,~0x18,        0x08,~0x18,
        0x01,~0x10,        0x10,~0x18,        0x08,~0x18,
        0x01,~0x20,        0x10,~0x18,        0x08,~0x18,
        0x01,~0x40,        0x10,~0x18,        0x08,~0x18,

        0x01,~0x80,        0x10,~0x18,        0x08,~0x18,
        0x02,~0x80,        0x10,~0x18,        0x08,~0x18,
        0x04,~0x80,        0x10,~0x18,        0x08,~0x18,
        0x08,~0x80,        0x10,~0x18,        0x08,~0x18,
        0x10,~0x80,        0x10,~0x18,        0x08,~0x18,
        0x20,~0x80,        0x10,~0x18,        0x08,~0x18,
        0x40,~0x80,        0x10,~0x18,        0x08,~0x18,
        0x80,~0x80,        0x10,~0x18,        0x08,~0x18,

        0x80,~0x02,        0x10,~0x18,        0x08,~0x18,
        0x80,~0x04,        0x10,~0x18,        0x08,~0x18,
        0x80,~0x08,        0x10,~0x18,        0x08,~0x18,
        0x80,~0x10,        0x10,~0x18,        0x08,~0x18,
        0x80,~0x20,        0x10,~0x18,        0x08,~0x18,
        0x80,~0x40,        0x10,~0x18,        0x08,~0x18,
        };


#define POWER PORTB
#define GND   PORTC

void port_init(void)
{
PORTB = 0xFF;
DDRB  = 0xFF;
PORTC = 0x00; //m103 output only
DDRC  = 0xFF;
PORTD = 0x00;
DDRD  = 0x00;
}

//TIMER0 initialize - prescale:64
// desired value: 1mSec
// actual value:  0.992mSec (0.8%)
void timer0_init(void)
{
TCCR0 = 0x00; //stop
TCNT0 = 0xC2; //set count
TCCR0 = 0x03; //start timer
}

#pragma interrupt_handler timer0_ovf_isr:10
void timer0_ovf_isr(void)
{
TCNT0 = 0xC2; //reload counter value

/*
**  将1种状态分3个小状态:
*/

POWER = LightTab[PowerLen][LightLen++];
GND   = LightTab[PowerLen][LightLen++];

if (LightLen == 6)
        LightLen = 0;

/*
**  整个过程分28种状态:
*/
Dtime200ms++;
if (Dtime200ms == 200)
        {
        Dtime200ms = 0;
        PowerLen++;
        if (PowerLen == 28)
                PowerLen = 0;
        }
}
发表于 2011-1-20 13:48:59 | 显示全部楼层
我也贴一个,写完发现跟83楼的思路一样
没有AVR,就用51的,SDCC代码


#include <at89x52.h>

unsigned int i=0,j=0;
volatile unsigned int t_cnt;

struct map_tag {
    unsigned char col;
    unsigned char row;
} map[30] = {
    {0b10000000,0b01111111},
    {0b01000000,0b01111111},
    {0b00100000,0b01111111},
    {0b00010000,0b01111111},
    {0b00001000,0b01111111},
    {0b00000100,0b01111111},
    {0b00000010,0b01111111},
    {0b00000001,0b01111111},
    {0b00000001,0b10111111},
    {0b00000001,0b11011111},
    {0b00000001,0b11101111},
    {0b00000001,0b11110111},
    {0b00000001,0b11111011},
    {0b00000001,0b11111101},
    {0b00000001,0b11111110},
    {0b00000010,0b11111110},
    {0b00000100,0b11111110},
    {0b00001000,0b11111110},
    {0b00010000,0b11111110},
    {0b00100000,0b11111110},
    {0b01000000,0b11111110},
    {0b10000000,0b11111110},
    {0b10000000,0b11111101},
    {0b10000000,0b11111011},
    {0b10000000,0b11110111},
    {0b10000000,0b11101111},
    {0b10000000,0b11011111},
    {0b10000000,0b10111111},
    {0b10000000,0b01111111},
    {0b00011000,0b11100111},
};

void timer0_init(void);
void delay(unsigned int t);

int main(void)
{
    timer0_init();

    while (1)
    {
        for (j = 0; j < 29; j++)
        {
            for (i = 0; i < 100; i++)
            {
                P2 = map[j].col;
                P1 = map[j].row;
                delay(1);
                P2 = map[29].col;
                P1 = map[29].row;
                delay(1);
            }
        }
    }
}

void timer0_init(void)
{
    /* 1ms */
    TCON = 0x10;
    TMOD = 0x01;
    TH0 = 0xFC;
    TL0 = 0x18;
    IE = 0x82;
    TCON = 0x10;
}   

void timer0(void) __interrupt TF0_VECTOR
{
    TH0 = 0xFC;
    TL0 = 0x18;

    t_cnt++;
}   

void delay(unsigned int t)
{
    t_cnt = 0;
    while (t_cnt < t);
}
发表于 2011-1-20 15:29:54 | 显示全部楼层
兴趣!发完贴,怎么感觉自己没有想自己做的项目里不是老用到数码管的显示吗?其实是一个道理,我就写了下面的代码。工作中我会用缓冲,但这里完全没有必要。

/*
**  可以自定义显示1个字符,
*/

const unsigned char MapTab[28][8]={
        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,0x18|0x01,0x18,0x00,0x00,0x00,
        0x00,0x00,0x00,0x18,0x18|0x01,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,0x18|0x80,0x00,0x00,0x00,
        0x00,0x00,0x00,0x18|0x80,0x18,0x00,0x00,0x00,
        0x00,0x00,0x80,0x18,0x18,0x00,0x00,0x00,
        0x00,0x80,0x00,0x18,0x18,0x00,0x00,0x00,
        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,
        };
unsigned char Map;
unsigned char Row;
unsigned char DTime200ms;
const unsigned char *pBuf=MapTab[0];

#define POWER PORTB
#define GND   PORTC


void port_init(void)
{
PORTA = 0x00;
DDRA  = 0x00;
PORTB = 0x00;
DDRB  = 0x00;
PORTC = 0x00; //m103 output only
DDRC  = 0x00;
PORTD = 0x00;
DDRD  = 0x00;
PORTE = 0x00;
DDRE  = 0x00;
PORTF = 0x00;
DDRF  = 0x00;
PORTG = 0x00;
DDRG  = 0x00;
}

//TIMER0 initialize - prescale:64
// WGM: Normal
// desired value: 1mSec
// actual value:  0.992mSec (0.8%)
void timer0_init(void)
{
TCCR0 = 0x00; //stop
ASSR  = 0x00; //set async mode
TCNT0 = 0xC2; //set count
OCR0  = 0x3E;
TCCR0 = 0x04; //start timer
}

#pragma interrupt_handler timer0_ovf_isr:17
void timer0_ovf_isr(void)
{
TCNT0 = 0xC2; //reload counter value

/*
**  根据马老师的提示要消隐.
*/
POWER = 0x00;
GND   = 0x00;

/*
**  将电源提供循环给出,数据同步得到给出.
**  将数据取反,给低电平灯会亮!
**  只要Map没有变,则一直显示当前画面!
*/
pBuf  = MapTab[Map]+Row;
POWER = 0x01<<Row;
GND   = ~*pBuf;

/*
**  地址选择循环
*/
Row++;
Row  &= 0x07;

/*
**  0.2s切换1个画面
*/
DTime200ms++;
if (DTime200ms == 200)
        {
        DTime200ms = 0;
        Map++;
        if (Map == 28)
                Map = 0;
        }
}
发表于 2011-1-20 15:31:34 | 显示全部楼层
有谁觉得代码的模块化,IO口调整性,程序扩展性,移植性,主要代码可读性(不加注释情况下),节能性等等比0我240L的代码好的?
有谁觉得中断中的代码比我还能少的?
=======================================================
以上仅为了引起注意,当然大家也可以当真挑战下,
不换个挑战点的写法,估计是没人理的....
 楼主| 发表于 2011-1-20 17:04:21 | 显示全部楼层
各位朋友,谢谢大家光顾此贴。不管是捧场的还是砸砖的,我都表示感谢。

好多朋友贴上了代码,可以看到许多人是非常用心的。我多么希望我现在教的学生能有这样的热情参与学习和讨论。

现在稍微透露我贴上此贴的一个“不可告人”的用意,那就是这个2个星期前的操作题,将在最后的笔试中再次出现。我教的学生中,有些人会经常到我的AVR讨论组来看看,下载实验要求、考试提纲,以及看些技术贴。我想真的喜欢学习和玩AVR的,想真正掌握些本事的,会对技术贴关心、思考、学习和研究。所以我就在考试前一天晚上送上这份不大也不小的“暗礼”。至于哪些学生能收到这份礼物,各位应该能想的出来。

其实此题最基本的目的是希望学生能掌握动态扫描的思想和使用,不管是8*8LED点阵、还是8个8段LED数码管显示,那个显示函数是通吃的。其实平时的实验中都有这个内容,哪个实验不用显示器?就看你平时是否都能自己独立的认真完成了。

实在抱歉,我没有时间细读所有的代码,我们考试的代码以及解释在上面已经贴出,各位可以参考和对比。此外,各位也不要局限我们的代码,看看其他朋友的代码,吸收众家的长处。
发表于 2011-1-20 17:24:29 | 显示全部楼层
回复【313楼】machao
-----------------------------------------------------------------------

用心良苦啊。

其实这个题就是显示一个8*8的字符,然后0.2秒切换一个字符就可以了。
发表于 2011-1-20 17:47:08 | 显示全部楼层
mark
发表于 2011-1-20 18:29:29 | 显示全部楼层
为什么我没遇到这样的老师啊....
发表于 2011-1-20 18:30:45 | 显示全部楼层
我晕…………
看着看着,直接到了270+楼!!!
中间那些呢????


马老师这个题不算很难吧~!
至少我觉得没那么难。
但是说俩小时嘛,这个还真不干打保票。
我做的话估计得调试个10、20分钟吧,也许运气好,一次成功。

看到270楼(其实是30+)觉得马老师觉得自己的学生水平不行啊。其实我是很想跟马老师学习,可是我已经大四,要工作的时候了……
俺这悲剧的学校啊……

有时间也整个!

再就是没看到157楼,都哪儿去了~
 楼主| 发表于 2011-1-20 19:07:29 | 显示全部楼层
顺便看了后面几个比较短的代码,都能实现题目要求。
提几个注意点:

1。定时器中断一般注意尽量使用CTC模式(51为自动重装),这样产生的定时中断精度才是最高的。使用溢出中断产生的中断比你设计的时间要长。——原因在于中断的响应是需要时间的!

    在此次考题第四大题有个问题,答案是“MCU开始响应中断到执行中断服务的第1条指令至少需要7个CLK”。这个还是从汇编的角度去看的。现在大家一般采用C编程,那么MCU开始响应中断到执行中断服务的第1个C语句就远远不是7个CLK了,因为C的编译器还要帮你加入中断现场保护的指令,这个时间由于程序的不同也是不同的。

    假定不考虑现场保护,设计为定时器计数100个CLK中断一次,采用溢出方式,到0xff产生中断,7个CLK后执行中断的第1条指令,你的第1条指令就是设置TCNT0 = 0xff-100;此条指令也需要1CLK。仔细想一下,那么下次中断的间隔为108个CLK。此时,中断的间隔不是100CLK,而是108CLK。如果考虑现场保护,这个时间还要长,而且还是变化的。更可怕的还有人在中断退出前才重设计数器的初值,这就更远了。

     而采用CTC方式,就不会产生这个问题,因为你没有人为的改变计数器的值。它计到100中断,并同时自动返回0。另外中断服务中至少减少了一句语句,效率还高了一点。

     现在回到本题:定时中断为1ms,考虑中断响应和现场保护时间,假定需要20clk,对于4M时钟,20CLK为0.005ms,那么实际中断间隔为1.005ms。设计为250ms移动一个LED,现在实际是251.25ms了。(这个分析其实不对,错在哪里请分析)

2。中断服务的代码要尽可能的短,这里是指执行时间短。由于LED扫描、按键扫描,对于时间精度要求不是非常严格,所以这些代码最好不要放在中断服务中。损失几个内存空间做标志变量,换来的是对整体软件系统的好处。比如,系统中使用多个中断,这样可能就不需要中断嵌套。要知道多个中断嵌套,往往会出现许多问题,而且还不容易找到原因。
发表于 2011-1-20 19:51:12 | 显示全部楼层
老马这个老师做的还真是不错的.很会引导学生去学习的.
发表于 2011-1-20 20:05:38 | 显示全部楼层
估计马老师放出这个大礼,没有几个学生能收到。这年头的学生除了会考试,就只会Ctrl+C,Ctrl+V,根本没耐心研究这些东西的。
说实话,坐在那里天天捣鼓的人,会被同学当成怪物。
 楼主| 发表于 2011-1-20 20:20:36 | 显示全部楼层
回复【319楼】ywl0409 老黄牛
老马这个老师做的还真是不错的.很会引导学生去学习的.
-----------------------------------------------------------------------

谢谢表扬了。

在学校我前后化了十几年的时间对这门课的进行了教学建设和改革。本课程获得了2009年上海市高校教学三等奖。注:要不是评选委员会中有我们学院的老师,这个三等奖也是没有的。获得一、二等奖的都是有头有脸的人物。

说老实话,对比那些一等奖、二等奖,我个人认为偶的课程超越他们。但从实际效果看,这个三等奖也受之有愧。对比Cornell University ECE 4760 课程 Designing with Microcontrollers,我教的学生水平连人家的1/3都不如。惭愧!

不是偶没有能力,是........
 楼主| 发表于 2011-1-20 20:58:13 | 显示全部楼层
回复【320楼】warmonkey
估计马老师放出这个大礼,没有几个学生能收到。这年头的学生除了会考试,就只会ctrl+c,ctrl+v,根本没耐心研究这些东西的。
说实话,坐在那里天天捣鼓的人,会被同学当成怪物。
-----------------------------------------------------------------------

我尽力了,良心上过的去。好多学生背后说我是“变态”
发表于 2011-1-20 21:28:12 | 显示全部楼层
回复【322楼】machao

回复【319楼】ywl0409 老黄牛
老马这个老师做的还真是不错的.很会引导学生去学习的.
-----------------------------------------------------------------------

谢谢表扬了。

在学校我前后化了十几年的时间对这门课的进行了教学建设和改革。本课程获得了2009年上海市高校教学三等奖。注:要不是评选委员会中有我们学院的老师,这个三等奖也是没有的。获得一、二等奖的都是有头有脸的人物。

说老实话,对比那些一等奖、二等奖,我个人认为偶的课程超越他们。但从实际效果看,这个三等奖也受之有愧。对比Cornell University ECE 4760 课程 Designing with Microcontrollers,我教的学生水平连人家的1/3都不如。惭愧!

不是偶没有能力,是........

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


马老师这番话让我颇有些心酸,我本科受到的专业教育等于零,研究生受到的专业教育等于负数。

如果不是自己对这一行有兴趣,多学了点东西,不知道要菜成什么样,都不好意思出去说是学电子专业的。

但是自学需要付出的精力和努力都是惊人的,所得却寥寥。要是有这样的老师,我想我本科也不至于荒废三年。
发表于 2011-1-20 21:46:26 | 显示全部楼层
回复【321楼】machao  
-----------------------------------------------------------------------

实际上很多人都是什么都不学的。。。
上机考拷过来的代码也看不懂
发表于 2011-1-20 22:14:42 | 显示全部楼层
"你的第1条指令就是设置TCNT0 = 0xff-100;"

that's the point that you have consistently missed.

you can change timer/counter registers without affecting its (long-term) accuracy, as long as you increment/decrement them, not assigning values to them, as you did before.

so in your case, if you did "TCNT0 += 0xff-100;" (or better yet, "TCNT0 += -100;"), your code will be as accurate as one with hardware reload (CTC on an avr for example).

that is very basic for an embedded programmer.
发表于 2011-1-20 22:58:59 | 显示全部楼层
回复【325楼】millwood0
-----------------------------------------------------------------------

//unsigned char disp_str[]="ABCBABBAC"; //ascii string to be displayed
//unsigned char *disp_str_ptr=disp_str; //display col index

If you want to emphasize the portable, than this code should never occur.

disp_str[]="ABCBABBAC" → disp_str[0]='A', disp_str[1]='B', ... ,disp_str[9]='C', disp_str[10]='\0'。

so, the last ASCII character, it is '\0'. If someone want to transplant your code to other platforms, and if this person doesn't have the programming level as you do, then this code would be misunderstood.
Then, from you point of view, you should set up a table for users to fill there content to display, and you should also define the number of characters to be displayed so that you can control the pointer in the program to avoid "overflow".
发表于 2011-1-20 23:03:55 | 显示全部楼层
回复【198楼】millwood0
-----------------------------------------------------------------------

Obviously, your code can only support 254 characters to display, but you never refered that in your code.
发表于 2011-1-20 23:06:59 | 显示全部楼层
"than this code should never occur. "

that piece of the code was originally written to display a moving string on a 8x8 matrix - unused here.

even put that aside, it's entirely portable as it is C and not hardware specific. and anyone having trouble understanding it shouldn't be programming anything.
发表于 2011-1-20 23:15:15 | 显示全部楼层
回复【328楼】millwood0
-----------------------------------------------------------------------

Really? Some programmers who works the high level programming doesn't know the difference of

display_str[]="ABC" and display_str[4]="ABC"

And even for a moving string display, you should also define the maximum number to be displayed, as the type you defined is unsigned char, mostly 255 characters, but the last character is "\0", so it can only support 254 characters.

Am I wrong? What if someone want to use your code to display a string which exceeds 254 characters?
发表于 2011-1-20 23:19:36 | 显示全部楼层
回复【45楼】machao
什么大学的?牛!数电实验用FPGA了。我们的大学培养了太多的高级傻瓜,90%的都是泡沫。

其实不管用什么,FPGA、DSP、还是MCU,思路基本是一样的。
-----------------------------------------------------------------------
晚辈不才
大学为哈工程(哈尔滨人一般叫“船院”)

中国的大多数大学生都是废物。
这个实验,我的答案被整个整个班的人抄袭(隔壁班的N多人也抄)
发表于 2011-1-20 23:48:13 | 显示全部楼层
"Am I wrong? "

yeah. in a typical C code, you would detect the end of a string with '\0'. so the user code would then revert back to the beginning or the next string, as it may be.

hardwiring the length of the string into your code makes the code not as flexible.

"you should also define the maximum number to be displayed, as the type you defined is unsigned char, mostly 255 characters, but the last character is "\0", so it can only support 254 characters. "

"unsigned char disp_str[]="ABCBABBAC";" only means that each character in disp_str[] is "unsigned char", and the string can be as long as you want - so long as the hardware permits.
发表于 2011-1-20 23:55:46 | 显示全部楼层
回复【331楼】millwood0
-----------------------------------------------------------------------

"unsigned char disp_str[]="ABCBABBAC";" only means that each character in disp_str[] is "unsigned char", and the string can be as long as you want - so long as the hardware permits.

I know this, but the pointer you defined "unsigned char *disp_str_ptr=disp_str", can disp_str_ptr exceed 255???
发表于 2011-1-21 00:01:35 | 显示全部楼层
马老师,我是微电子专业的学生
按我们半导体物理老师的说法,您这门课就是给中专生开的。。。您觉得呢?这老师长江学者啊
半导体老师经常抱怨,这神马学校,越来越像中专了,本科生连个量子物理都不学。
微电子和电子信息和软件的确是三个完全不同的专业呀。
so,虽然您是马老师,您不懂微电子
发表于 2011-1-21 00:06:24 | 显示全部楼层
回复【331楼】millwood0
-----------------------------------------------------------------------

The bit length of the pointer is relevant to the platform itself, if you use 8-bit MCU, then the bit length of the pointer is 8-bit, so how portable your code is, it can only support 254 characters to display.

I am wrong again? hehe~
发表于 2011-1-21 00:13:43 | 显示全部楼层
"I know this, but the pointer you defined "unsigned char *disp_str_ptr=disp_str", can disp_str_ptr exceed 255???"

you may think you know but your question clearly shows that you don't.

disp_str_ptr is simply a pointer to a char somewhere in memory. how  many chars follow the char that disp_str_ptr points to and where the string of those chars ends is up to you (and the platform).

so to answer your question, for the 4th time, yes, the string that disp_str_ptr points to can be longer than 255.

"The bit length of the pointer is relevant to the platform itself, if you use 8-bit MCU, then the bit length of the pointer is 8-bit, so how portable your code is, it can only support 254 characters to display.

I am wrong again? hehe~"

yes,  you are wrong again.
发表于 2011-1-21 00:15:32 | 显示全部楼层
memo to self:

never send my kids to "East China Normal University"

:)
发表于 2011-1-21 00:33:18 | 显示全部楼层
回复【336楼】millwood0
-----------------------------------------------------------------------
OK, so you would be a good programmer, but you are not a good teacher.

I ask you this question in purpose, I want to know how you answer me, so no matter how you satirize me, I never mind.

Let me explain the pointer. Why a pointer defined as 8-bit length can point to the memory address that exceeds 255.

Take 80X86 for example, in 16-bit mode, the address is defined as the combination of two 16-bit binary numbers, that is sector address and offset.
If your compile environment is small, and you defined only one data segment, the sector address if fixed. The offset is 16-bit variable.
However, if you change the compile environment to large, the pointer would be 32-bit, which contains the sector address and offset.

Then, you can explain what you called as hardware limits.
发表于 2011-1-21 00:33:54 | 显示全部楼层
回复【336楼】millwood0
-----------------------------------------------------------------------
OK, so you would be a good programmer, but you are not a good teacher.

I ask you this question in purpose, I want to know how you answer me, so no matter how you satirize me, I never mind.

Let me explain the pointer. Why a pointer defined as 8-bit length can point to the memory address that exceeds 255.

Take 80X86 for example, in 16-bit mode, the address is defined as the combination of two 16-bit binary numbers, that is sector address and offset.
If your compile environment is small, and you defined only one data segment, the sector address if fixed. The offset is 16-bit variable.
However, if you change the compile environment to large, the pointer would be 32-bit, which contains the sector address and offset.

Then, you can explain what you called as hardware limits.
发表于 2011-1-21 00:52:56 | 显示全部楼层
"Why a pointer defined as 8-bit length can point to the memory address that exceeds 255. "

a pointer to a char (unsigned or otherwise) can be of any bit length, depending on the hardware. next time, try to use a sizeof() on a pointer to a char and see for yourself.

you can also have a pointer to void (aka of no size). yet, you can use that void pointer to point to anything your heart desires.

what you couldn't understand is that a) an 8-bit mcu can have much wider addressable space; and b) the type of a pointer has no relation to how long the subject it points to is.

"Then, you can explain what you called as hardware limits."

unfortunately, I don't offer free lessons.
发表于 2011-1-21 01:01:43 | 显示全部楼层
回复【325楼】millwood0  
"你的第1条指令就是设置tcnt0 = 0xff-100;"

that's the point that you have consistently missed.

you can change timer/counter registers without affecting its (long-term) accuracy, as long as you increment/decrement them, not assigning values to them, as you did before.

so in your case, if you did "tcnt0 += 0xff-100;" (or better yet, "tcnt0 += -100;"), your code will be as accurate as one with hardware ......
-----------------------------------------------------------------------

I do not think that this method can be compared with CTC. This method is only practical when the accurate executing time from reading the counter value and write it back. If a nesting interrupt is invoked, the executing time will be unpredictable.
Beside, if there is a pre-scaler, or even the clock source is an external one, the problem will be tougher.      


(原文件名:Capture.PNG)
发表于 2011-1-21 01:02:14 | 显示全部楼层
回复【339楼】millwood0
-----------------------------------------------------------------------

try to use a sizeof() on a pointer to a char and see for yourself.

sizeof() depends on the complier, still take 8086 as example, as I refered in the previous reply.

You choose the mode of the complier as small, in this mode, for example:

char *pointer;

Then, sizeof(pointer)=2, this result only represents the length of the offset, however, if you change the mode of the complier as "large", then, sizeof(pointer)=4, which contains the segment address and the offset.

"unfortunately, I don't offer free lessons."

Even if you offer a free lesson, maybe nobody dare to attend it for your teaching method.
发表于 2011-1-21 01:22:15 | 显示全部楼层
"Then, sizeof(pointer)=2, this result only represents the length of the offset, however, if you change the mode of the complier as "large", then, sizeof(pointer)=4, which contains the segment address and the offset. "

that's the point. the size of the pointer can be drastically different from the size of the subject that the pointer points too. in your case, the size of the pointer is either 16 bits (sizeof()=2), or 32 bits (sizeof()=4). yet, in both cases, the size of the subject that the 16-bit/32-bit pointer points to is 8 bits.

"Even if you offer a free lesson, maybe nobody dare to attend it for your teaching method."

since it is not offered, there is no point in you worrying about it.

"I do not think that this method can be compared with CTC. This method is only practical when the accurate executing time from reading the counter value and write it back."

it does assume atomic reading / writing of the register. which is true in normal interrupt handling.

" If a nesting interrupt is invoked, the executing time will be unpredictable."

agreed. in that case, you have to guard against in-atomicity: not an issue with registers that can be read / write in one instruction (8-bit registers on an 8-bit mcu, or a 32-bit register on a 32-bit mcu). But if you want to read a multi-byte register in an 8-bit mcu, you need to turn off the interrupt before the read and turn on the interrupt after the read.

"Beside, if there is a pre-scaler, or even the clock source is an external one, the problem will be tougher.   "

those are non-issues.
发表于 2011-1-21 01:25:15 | 显示全部楼层
回复【331楼】millwood0  
"am i wrong? "

yeah. in a typical c code, you would detect the end of a string with '\0'. so the user code would then revert back to the beginning or the next string, as it may be.

hardwiring the length of the string into your code makes the code not as flexible.

"you should also define the maximum number to be displayed, as the type you defined is unsigned char, mostly 255 characters, bu......
-----------------------------------------------------------------------

I agree that the pointer can point to any address within the memory. But the compiler may allocate the following space to other variables. So the string can only be modified to shorter or same length. The command "malloc" may solve the problem with a larger memory.
发表于 2011-1-21 01:33:00 | 显示全部楼层
"But the compiler may allocate the following space to other variables. So the string can only be modified to shorter or same length. The command "malloc" may solve the problem with a larger memory."

depending on which perspective you are taking (from a mcu perspective or from a cpu perspective), you may react differently to the above statement.

however, that's irrelevant in this discussion: whether a string pointed to by a char pointer can be longer than 255 characters, hardware limitations aside.
发表于 2011-1-21 01:43:50 | 显示全部楼层
回复【342楼】millwood0  
"I do not think that this method can be compared with CTC. This method is only practical when the accurate executing time from reading the counter value and write it back."

it does assume atomic reading / writing of the register. which is true in normal interrupt handling.

" If a nesting interrupt is invoked, the executing time will be unpredictable."

agreed. in that case, you have to guard against in-atomicity: not an issue with registers that can be read / write in one instruction (8-bit registers on an 8-bit mcu, or a 32-bit register on a 32-bit mcu). But if you want to read a multi-byte register in an 8-bit mcu, you need to turn off the interrupt before the read and turn on the interrupt after the read.

"Beside, if there is a pre-scaler, or even the clock source is an external one, the problem will be tougher.   "

those are non-issues.
-----------------------------------------------------------------------
The problem is that TCNT0-=1 is NOT a atomic instruction. It takes times.
If the prescaler is set to divide the clock by 8, how can you make up for the 5 clocks? The value in the prescaler is invisible and can only by manipulated by the rough reset and synchronization command.
发表于 2011-1-21 01:46:00 | 显示全部楼层
回复【344楼】millwood0
-----------------------------------------------------------------------

"depending on which perspective you are taking (from a mcu perspective or from a cpu perspective), you may react differently to the above statement."

Even in MCU, you should assign the memory space resonably. Variables that would be changed frequently used to be allocate the SRAM space, but for the fixed data, you can store them in the flash.

for example:

//unsigned char disp_str[]="ABCBABBAC"; //ascii string to be displayed  
//unsigned char *disp_str_ptr=disp_str; //display col index  

can be changed to:

flash unsigned char disp_str[]="ABCBABBAC";
flash unsigned char *disp_str_ptr = disp_str;

Put those variables which have fixed value into flash would save more SRAM space for other usage.
发表于 2011-1-21 01:46:24 | 显示全部楼层
回复【344楼】millwood0
-----------------------------------------------------------------------

"depending on which perspective you are taking (from a mcu perspective or from a cpu perspective), you may react differently to the above statement."

Even in MCU, you should assign the memory space resonably. Variables that would be changed frequently used to be allocate the SRAM space, but for the fixed data, you can store them in the flash.

for example:

//unsigned char disp_str[]="ABCBABBAC"; //ascii string to be displayed  
//unsigned char *disp_str_ptr=disp_str; //display col index  

can be changed to:

flash unsigned char disp_str[]="ABCBABBAC";
flash unsigned char *disp_str_ptr = disp_str;

Put those variables which have fixed value into flash would save more SRAM space for other usage.
发表于 2011-1-21 01:52:24 | 显示全部楼层
回复【347楼】tearsman520  消逝的岁月
-----------------------------------------------------------------------

是的,但是做串口缓冲的时候,没办法。只好定义一个buf[50]了.
发表于 2011-1-21 01:56:44 | 显示全部楼层
回复【348楼】iamseer
-----------------------------------------------------------------------

呵呵,看你的应用而定啦,缓冲区的长度和应用中要求的数据更新速度有关系的。
我用ATmega16读SD卡打印文本的时,缓冲区长度只定义了8个字节,不用缓冲区都可以……
涉及到读写操作都没办法的事情……=.=
发表于 2011-1-21 02:06:25 | 显示全部楼层
"The problem is that TCNT0-=1 is NOT a atomic instruction. It takes times."

that's an issue with nested interrupts. but not an issue with regular interrupt handling.

"If the prescaler is set to divide the clock by 8, how can you make up for the 5 clocks? The value in the prescaler is invisible and can only by manipulated by the rough reset and synchronization command."

the same is true with CTC as well: if you had set the prescaler to 1:8, the minimum number of ticks a timer can be triggered under CTC is 1*8=8.

so prescaler is a non-issue here.

hardware reload does have one advantage over software reload: when the interrupt is rapidly firing. because of interrupt latency, a software reload may not happen fast enough.

For example, if your software latency is 0x0f (timer ticks). and your off set is 0xf5 (for an expected timer ticks of 5), the resulting timer/counter (from TMR+=0xf5) would be 0x05, giving you an unexpected timer ticks of 0xfa.

hardware reload doesn't suffer from that.
发表于 2011-1-21 02:08:29 | 显示全部楼层
回复【349楼】tearsman520  消逝的岁月
-----------------------------------------------------------------------

这。。。 我觉得没必要为省而省。对于就烧一个的代码,尤其是课堂给定任务的实验,直接顶配比较好。我当时是在16M+mega328的Arduino上跑代码的。核心算法远比省这点资源有用。电流、效率、空间都不重要,能快速出结果才是王道。
发表于 2011-1-21 02:18:52 | 显示全部楼层
回复【351楼】iamseer
-----------------------------------------------------------------------

是啊,但单片机编程还是不同于PC编程的,能省则省咯。后来做WAVE播放器,由于采样率和SPI速率的限制,缓冲区的大小就有讲究了,太小就不行了……
发表于 2011-1-21 02:43:05 | 显示全部楼层
回复【350楼】millwood0  
-----------------------------------------------------------------------

What matters is that you do not know and you will never know whether there will be a pulse from the prescaler. This will cause accumulated error.
But I guess manipulate the counter at the beginning of the ISR routine will help. As long as there are not coincidental numbers of "push" commands inserted by compiler.
Tiny13 Interrupt for 10 times:


(原文件名:Capture2.PNG)


(原文件名:Capture.PNG)
发表于 2011-1-21 02:47:58 | 显示全部楼层
"flash unsigned char disp_str[]="ABCBABBAC";
flash unsigned char *disp_str_ptr = disp_str;"

no, you shouldn't do that.

disp_str[] is structured as a display buffer, as its name implies. As such, its content is supposed to change - so it should reside in SRAM.

the same goes with disp_str_ptr.
发表于 2011-1-21 02:50:32 | 显示全部楼层
"hat matters is that you do not know and you will never know whether there will be a pulse from the prescaler. "

I don't know why you need to know that.

"This will cause accumulated error."

how?
发表于 2011-1-21 02:58:22 | 显示全部楼层
"Put those variables which have fixed value into flash would save more SRAM space for other usage."

yeah, if and only if those "variables" have fixed value.

in this case, they don't. so you cannot put them in flash.
 楼主| 发表于 2011-1-21 03:01:09 | 显示全部楼层
回复【333楼】li900309
马老师,我是微电子专业的学生
按我们半导体物理老师的说法,您这门课就是给中专生开的。。。您觉得呢?这老师长江学者啊
半导体老师经常抱怨,这神马学校,越来越像中专了,本科生连个量子物理都不学。
微电子和电子信息和软件的确是三个完全不同的专业呀。
so,虽然您是马老师,您不懂微电子
-----------------------------------------------------------------------
哦,偶是不懂“微电子”啦。

你是华东师大的学生吗?我们学院的微电子专业3年前就已经专门成为一个独立的系了,我承担的《微机原理》和《嵌入式系统》是学院规定的专业平台课,当时微电子专业就说不准备开设了。可是我拿到的最新2011年招生的本科计划中,微电子专业还是开设了这两门“中专生”的课程。长江学者可比我的能量大,他一句话就可以不开中专的课程了,为什么计划中还要开设?微电子专业的教学计划可不是我制定的,本身就是微电子专业的老师制定的,为什么?不懂,你多想想吧。

现在的学校的确是神马学校,知道神马学校的含义吗?那就是学生是神马,老师是神马,长江学者更是神马了!这个你懂么?

我只是一个普通的教师、副教授而已,不懂微电子。可我懂得这样的基本常识:只有学校的管理层是神马才会使学校成为神马学校的。我说的对吧。

那么谁在管理学校?院士、博导、长江学者、紫江学者们呀。你的那个长江学者老师好象是副校长吧,他不是神马的话,学校怎么会成为神马的?

因此当一个神马说别人是神马的话,哪个被说的人肯定不是神马,转过来了吗?哈哈。
发表于 2011-1-21 03:20:03 | 显示全部楼层
回复【354楼】millwood0
-----------------------------------------------------------------------

You misunderstood what I really mean.

Yes, you refered that the content of  disp_str[] is used to display a character, and users (not your own code) may want to change the content, but if your code would not change it, then it is safe to allocate the flash space to it.

However, if you want to change the content in your program, it must be allocated in SRAM.
发表于 2011-1-21 03:25:04 | 显示全部楼层
"but if your code would not change it, then it is safe to allocate the flash space to it."

but my code IS supposed to change it. that's what a "buffer" is.

"However, if you want to change the content in your program, it must be allocated in SRAM. "

no one wants to change the content of the program. Just the content of that particular variable so a user can display whatever s/he wants by changing the content of the buffer.

that's the whole / sole purpose of this code.
发表于 2011-1-21 03:40:22 | 显示全部楼层
回复【359楼】millwood0
-----------------------------------------------------------------------

“no one wants to change the content of the program. Just the content of that particular variable so a user can display whatever s/he wants by changing the content of the buffer. that's the whole / sole purpose of this code.”

OK, I reviewed your code and this time I really made a bad mistake~~=.=
发表于 2011-1-21 04:32:53 | 显示全部楼层
here is an example that you can run to help you understand what we have been talking about.

========code===========
/*
*/

#include <avr/io.h>
//#include "gpio.h"

unsigned char str[]=
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "01234567890123456789"
        "abcdefghijklmnopqrst"
;

unsigned char * str_ptr=str+600;                        //pointing to the 600th number from the beginnging of str[0]

void mcu_init(void) {                                                //reset the mcu
}

int main(void) {

        mcu_init();                                                                //reset the mcu

        while(1) {
        }

        return 0;
}
======================

str[] is a string of 620 characters, filled with 0..9 except that last 20 chars.

str_ptr is a pointer to a char, and in this case, pointed to the 600th chars in str[] (str itself is actually a pointer). so *str_ptr should be 'a'.

so here is a case where on an 8-bit mcu, we have a pointer to a "unsigned char" that points to a string that is far greater than 255.
发表于 2011-1-21 09:03:45 | 显示全部楼层
回复【355楼】millwood0  
"hat matters is that you do not know and you will never know whether there will be a pulse from the prescaler. "

i don't know why you need to know that.

"this will cause accumulated error."

how?


-----------------------------------------------------------------------
... the RED numbers in the two screen shots are DIFFERENT.
发表于 2011-1-21 09:41:58 | 显示全部楼层
they should be different, as the "nop" instructions artificially increased the latency before the tnct0 increment instruction is executed.

the missing 80 cycles are 5 nop instructions over 1:8 clock prescaler.
发表于 2011-1-21 10:00:53 | 显示全部楼层
回复【363楼】millwood0  
they should be different, as the "nop" instructions artificially increased the latency before the tnct0 increment instruction is executed.

the missing 80 cycles are 5 nop instructions over 1:8 clock prescaler.
-----------------------------------------------------------------------

So?

(原文件名:Capture.PNG)
发表于 2011-1-21 10:36:40 | 显示全部楼层
回复【361楼】millwood0
-----------------------------------------------------------------------

Thanks for your explaination, I know that the pointer which is defined as unsinged char can point to a string greater than 255, I said that I asked you such question in purpose, and I just want to explain it from the 80X86's point of view.

:)
发表于 2011-1-21 11:48:49 | 显示全部楼层
马老师应该要去南方科技大学,否则就是浪费~
发表于 2011-1-21 12:10:35 | 显示全部楼层
回复【366楼】Candlelook
-----------------------------------------------------------------------

开设博士学位么……^_^  朱清时……牛X
 楼主| 发表于 2011-1-21 12:15:02 | 显示全部楼层
【366楼】,谢谢了。

不过我只有教的中专水平,还是请长江学者去吧。现在我不是活的还不错吗,3点到10点,7个小时的睡眠,然后精神十足的又来打口水战了 :)
发表于 2011-1-21 13:14:34 | 显示全部楼层
我给个提纲吧:

分析题目,最多只有三行, 因而可以定义以下的结构:
struct{
  unsigned char row;
  unsigned char val;
}TLED;

/*led共有28个状态(4*7),每个状态最多有三行
  其中:Vx_1表示各流水灯的点亮位置值,Vx_2,Vx_3就是中间四个LED的值了,
  其实这里可以只要一个值,因为本题Vx_2=Vx_3,且列值也相同,为说明问题
  而用三值。
*/
TLED led_status[28][3]={{v1_1,v1_2,v1_3},{v2_1,v2_2,v2_3}....{v28_1,v28_2,v28_3}};


//定义一个状态字并设初值为0
unsigned char status=0;

//定义端口,如PA,PB  (注意,PA,PB只是一个符号,实际电路图请修改设置)
#define ROW     PA
#define VAL     PB

//定义计时器
UINT8 msCount;    //200mS

//接下来,设置定时器中断:
//定时器时长,4ms左右,保证LED灯不闪,假定为4毫秒
TimerX:
{
unsigned char i

  for(i=0;i<3;i++)
  {
    ROW=led_Status[status][0].row;
    VAL=led_Status[status][0].val;
  }
  msCount+=4;
  msCount%=200;
  if(msCount==0x00)
  {
    status++;
  }
}
发表于 2011-1-21 14:01:15 | 显示全部楼层
回复【368楼】machao  
-----------------------------------------------------------------------
没有不尊敬您的意思,大家都觉得做的东西最好,都有的轻视别人的劳动

院士是这样长江学者是您也是
 楼主| 发表于 2011-1-21 14:44:52 | 显示全部楼层
轮到我来盖楼了:)

由于锻炼机会少偶写E文经常会出现错字和语法错误,速度也慢,还是中文吧。好在millwood0、iamseer、tearsman520都看的懂中文,另外也是让其它更多的朋友能真正理解关键所在。

一、millwood0和iamseer讨论的主题是:定时器中断使用哪种方式更精确?
   
   再次强调我的观点:使用CTC模式,也就是自动重装模式(hardware reload)!

   millwood0提出的使用溢出中断,在中断中采用 TCNT0 += 0x02;与CTC模式等同是不正确的。道理如下:
   
   1。首先一条,也是最简单的,采用CTC模式的话,中断服务程序中可以少用至少一条指令,甚至是多条指令。提高效率,符合中断服务代码尽量短的原则。

   2。 如果不考虑上面一点,那么“溢出中断+TCNT0 += 0x02”与“CTC中断”的精度一样吗?错也!请看下面代码:

      ;0000 0015   TCNT0 = 0x05;
        LDI  R30,LOW(5)
        OUT  0x32,R30
      ; 0000 0016
      ; 0000 0017   TCNT0 += 0x05;
        IN   R30,0x32
        SUBI R30,-LOW(5)
        OUT  0x32,R30
      ; 0000 0018
      这是CVAVR编译后的汇编代码,大家注意 TCNT0 += 0x05;产生的汇编为3句,其中0x32是TCNT0的寄存器地址。

      汇编代码是将TCNT0的值读出,然后加上5,最后回写到TCNT0中。关键问题在这里!当你把TCNT0的值读出后,在做加5的时候,就会产生TCNT0也自动加了1了。但你读到的还是原来的TCNT0的值,加上5回写的话,那么肯定时间就不准确了。

      是否把可以把TCNT0 += 0x05设置成“原子”操作?根本办不到!原子操作是软件层面上概念,指某段代码的执行过程中不能“其它”的代码打断,更深的意义是“原子操作段代码中所使用的变量值,在本代码段的执行过程中不能被别的代码更改”!但是计数器的自动加1是硬件自动完成,你软件能控制吗?要控制就是停止计数器工作,那么定时将更加不准确。

      如果使用AVR的16位计数器,这样的情况产生概率会更高,因为AVR是8位的内核,操作16位数据需要更多的指令,而且还根本无法做到什么原子操作。

      millwood0曾说到不要人为的改动计数器,但他的“timer += 0xXX”恰巧违背了这一点。只有当timer是软件计数器的话,这样使用是可以的,因为你可以把timer += 0xXX设置成原子操作,但在这里我们讨论的是硬件计数器。

      iamseer找到了出问题的现象,可是他没有说到点子上。在353楼他的2个贴图中,为什么加了5个NOP会增加80个CLK呢?因为他的时钟是8分频的,增加5个NOP后,使得后面执行TCNT0+=128过程中恰巧发生我上面提到的现象,这样的话每次少了加了1,10次就是少10个计数脉冲,每个计数脉冲为8个CLK,所以增加了80个CLK。而346楼的图中加了9个NOP,把这个TCNT0+=128过程与TCNT0自动加1错开了,时间所以又对了,回到了10240。

===================================================
所以,还是CTC吧,没有那么多的罗嗦事情。
   
Gorgon Meducer说我老调重弹,还是讨论定时准确的问题。是的,定时不准确你的系统的可靠性就有问题,测频率、周期、速度、转速,定时不准,你的测量控制还准吗?
 楼主| 发表于 2011-1-21 15:06:39 | 显示全部楼层
回复【370楼】li900309
-----------------------------------------------------------------------
没有不尊敬您的意思,大家都觉得做的东西最好,都有的轻视别人的劳动
院士是这样长江学者是您也是
-----------------------------------------------------------------------
错了。我在兢兢业业的做我自己的事情,并没有轻视别人的劳动。我没有说过任何人是“中专”水平,神马学校也不是我下的定义。

尽管我这门课是给中专生开的,那么你学的如何?达到中专的水平吗。

尊敬不尊敬,看的起看不起是你自己的事情。至少你在这个技术贴中333楼的发言是不和谐的。370楼的DD也是不和谐的。你得不到我的尊重,不受欢迎。从这个角度看,你连中专生素质都达不到。
发表于 2011-1-21 15:16:00 | 显示全部楼层
to 【371楼】 machao
    虽说是老调重弹……但是从现在的状况来看……很有必要每个人都要看一看……
而且很多人并没有真正理解其中的思维模式……估计马老师下次再把这个问题换个马甲
又会有不少人继续上当了……
发表于 2011-1-21 15:29:48 | 显示全部楼层
回复【372楼】machao  
-----------------------------------------------------------------------

你是这个方面的专家没错,这个问题我是来学习的

但你就能保证你什么都懂?天文地理你都是专家?

在你的研究领域我是小学生,我向你学习;在别的领域呢?您有没有需要谦虚学习的东西?

作为一名教师你把话说重了,说难听了,你看不起别人也会有别人看不起你
发表于 2011-1-21 15:47:22 | 显示全部楼层
“可我懂得这样的基本常识:只有学校的管理层是神马才会使学校成为神马学校的。我说的对吧。

那么谁在管理学校?院士、博导、长江学者、紫江学者们呀。你的那个长江学者老师好象是副校长吧,他不是神马的话,学校怎么会成为神马的?”

对,学校的管理有很大问题,教学行政科研搅在一起,中_国教育毛病大了

中国也就你兢兢业业,不懂不要瞎说,我说的人就是个也是个勤勤恳恳兢兢业业埋头搞理论研究的人,没有行政职务有他也做不好,就是个“书呆子”,但是可悲的是这样的书呆子太少了。。。
他说这些话也就是抱怨,抱怨我_国搞科研的不得志,行政的很风光,抱怨领导为了追求就业率砍理论课,抱怨学生浮躁不爱学习...



[我不是华东师大的学生]
 楼主| 发表于 2011-1-21 15:50:07 | 显示全部楼层
回复【373楼】Gorgon Meducer 傻孩子
    虽说是老调重弹……但是从现在的状况来看……很有必要每个人都要看一看……
而且很多人并没有真正理解其中的思维模式……估计马老师下次再把这个问题换个马甲
又会有不少人继续上当了……
-----------------------------------------------------------------------

以前说过这个问题,没有这样的深入,只是提倡大家使用CTC模式。其实此贴开始也不是讨论这个的。

至于思维模式的不同主要是大家的出身不同。现在很多的嵌入式系统程序员是学软件的,所以更加注意和强调软件层面上的东西,比如可移植性,通用性,原子操作,而忽视了硬件低层的不同。而硬件工程师通常软件上面比较弱,往往忽视软件层面上的问题,即便能发现问题,但也可能说不清楚为什么。

但实际上嵌入式系统两者结合的太紧密了,单纯从某个角度看都会产生一些片面的思维。
 楼主| 发表于 2011-1-21 16:40:38 | 显示全部楼层
回复【374楼】li900309

你是这个方面的专家没错,这个问题我是来学习的

    一个教中专课程的教师能称的上是专家吗?谢谢你的提携。你问的什么技术问题?在哪个楼面?我知道的一定回答。  

但你就能保证你什么都懂?天文地理你都是专家?

     这个我说过吗?扣帽子了。

在你的研究领域我是小学生,我向你学习;在别的领域呢?您有没有需要谦虚学习的东西?
     
     教中专的还有研究领域?你又提携我了。的确我要学习的东西还有很多,应该能力,争取早日成为长江学者,去申请自然科学基金项目。
  
作为一名教师你把话说重了,说难听了,你看不起别人也会有别人看不起你
         
    给你回贴已经是看的起你了。

-------------------------------------------------------------------------------------
“可我懂得这样的基本常识:只有学校的管理层是神马才会使学校成为神马学校的。我说的对吧。

那么谁在管理学校?院士、博导、长江学者、紫江学者们呀。你的那个长江学者老师好象是副校长吧,他不是神马的话,学校怎么会成为神马的?”

=======》最先定义神马学校的可是你或你的老师定义的,如果学校是神马,责任当然是领导层。也错了?

--------------------------------------------------------------------------------------
对,学校的管理有很大问题,教学行政科研搅在一起,中_国教育毛病大了

中国也就你兢兢业业,不懂不要瞎说,我说的人就是个也是个勤勤恳恳兢兢业业埋头搞理论研究的人,没有行政职务有他也做不好,就是个“书呆子”,但是可悲的是这样的书呆子太少了。。。

======》我什么时候说中国“就”我兢兢业业了?我说过你的老师不“勤勤恳恳兢兢业业”,看不起你的老师吗?看不起别人的正是你的老师,把学院开设的课程说成是“中专”水平。这个可是你透露的。

====》“大家都觉得做的东西最好,都有的轻视别人的劳动。院士是这样长江学者是您也是”也是你说的。

====》我不懂,瞎说。你懂,你没有瞎说。可是我满眼看到你的帖子都是瞎说。

====》小伙子,如果你认为你的老师非常厉害,那就不要到这个中专水平的地方来浪费时间了。好好的跟着你的老师学习吧,做他的研究生、博士生、将来也会成为长江学者的。
发表于 2011-1-21 17:10:03 | 显示全部楼层
回复【377楼】machao  
-----------------------------------------------------------------------

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

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

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

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

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

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

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

撤退看书去,我手下败将,高兴了?
发表于 2011-1-21 18:21:12 | 显示全部楼层
想当日乔峰与天下中英雄在聚贤庄喝绝义酒,当与众英雄喝毕,苟且之辈向往海对乔峰说道;姓乔的,我也与你喝一杯。
乔峰斜眼望去,说道;乔某与天下英雄喝这绝交酒,乃是将往日恩义一笔勾销之意,你我有何交情?凭你也配和我喝这杯绝交酒?
 楼主| 发表于 2011-1-21 18:25:45 | 显示全部楼层
接371楼,看millwood0和tearsman520的讨论。

先需要说明的是tearsman520目前是偶的学生,学习专业以硬件为主,在软件层面,尤其深入的东西了解的并不透。所以他们两人的对话好象没有主要重点。面对tearsman520的一些“傻”问题,millwood0还能耐心的跟他饶圈,非常难得,也是热心人。

我汇总2点,不知道对否。

一、关于指针问题。
    从软件理论上说,指向char的指针是可以指到任何地方的,没有长度的限制,这个没有错。而在实际情况中,由于受到硬件和编译器的限制,并不是如此。我们知道指针本身也是一个变量,它的值实际是储存器的地址。是变量就需要在内存中分配地址单元保存数据,那么分配给指针变量的大小是几个字节?这个是隐含的,不象CHAR、INT那么明显,要看硬件和编译器了。下面一段是摘自CVAVR的HELP中的规定:
     
In order to improve the code efficiency several memory models are implemented.

The TINY memory model uses 8 bits for storing pointers to the variables placed in RAM. In this memory model you can only have access to the first 256 bytes of RAM.

The SMALL memory model uses 16 bits for storing pointers the variables placed in RAM. In this memory model you can have access to 65536 bytes of RAM.

OK!很明显,指针是有长度的。如果你在TINY模式下,对指针操作,超过256就会出现问题了。如果编译器好,会给你个错误提示。如果编译器做的不好,那么程序运行就出问题了:因为你认为指的是第256个单元,其实指的是第0个单元。这样的BUG也是非常难找的。

二、关于字符数组的长度问题
    有许多人在这个问题上容易忽视,看下面2个定义:
   
    flash char str_1[] = "0123";
    flash char str_2[4] = {'0','1','2','3'};

    好象都定义了一个“1234”的字符串,那么str_1的长度是多少?4个?不对,5个!看在储存器中分配:
    _str_1:
        .DB  0x30,0x31,0x32,0x33,0x0
    _str_2:
        .DB  0x30,0x31,0x32,0x33
  
    C中严格的定义是:str_1是一个字符串变量,而str_2是一个4个单元的字符数组。标准的C会给字符串后面加上0x00的,作为字符串的结束标志,所以长度上多了1个。

    那么在应用中注意什么?比如你使用系统标准的一个PRINT函数,那么只要你把str_1的指针传递过去就可以了,标准的PRINT函数中会自动判别0x00,然后停止。但如果你把str_2的指针传给PRINT函数,那么可能这个PRINT就停不下来了。

三、分配到FLASH中还是RAM中。
    由于对于小的8位MCU,FLASH相对比RAM大些,所以把固定不变的字符串,或字符数组分配到FLASH中,可以让出比较多的RAM,也是常用的方法。但此时,你就不能使用上面的PRINT函数了,必须使用针对FLASH的PRINT函数来输出,或自己编写了。当然就谈不到兼容性了。

======================================================
最后谈谈兼容性的问题。
   
    由于标准C是在8086基础上发展的。8086的程序和数据都在RAM中。而8位的51、AVR等,程序空间和数据空间是不同的物理空间,分别编址的,况且硬件本身也是不同,因此作为C要兼容是非常困难的。这也是为什么现在的32位系统和新的MCU把程序空间和数据空间进行统一编址的原因之一吧,这样C的兼容性会好一些。

    还有许多原因制约着兼容性的问题,比如压堆栈后指针是加还是减,有的MCU清除中断标志位是写0,而有的是写1清除。因此过分强调兼容、可移植就片面了。这个不是PC上的程序,不管8086,还是80586,在硬件环境上它们就是兼容的,所以软件也容易兼容和移植。而嵌入式系统的代码,硬件本身不兼容,要求软件兼容、可移植就更加困难了。

    所以我个人的观点是,对于用户层面的代码,可以更多的考虑可移植性,通用性,而对于底层的代码,还是少考虑可移植性为好。我认为更重要的是一种方法的兼容和可移植性,比如本贴开始的8*8LED动态扫描的思想方法,对于任何的MCU都是兼容的。

    不了解millwood0编写过51的代码吗?在KEIL中对于51也支持bit类型的变量,如果你使用了bit类型的变量,那么代码的可移植性就差多了。我做的许多AVR项目,大部分是在CVAVR中完成的,如果交给millwood0肯定也不及格,因为我比较喜欢定义BIT变量作为标志变量,一个字节可以保存8个BIT变量,节省RAM。但肯定可移植性就差多了。
 楼主| 发表于 2011-1-21 19:10:29 | 显示全部楼层
回复【378楼】li900309

你对 教授啊 博士学者之类的一直耿耿于怀,他们跟你做的就不是一种工作,科学和技术是不一样的。。。  
===》我本人是副教授,自己对自己耿耿于怀,可能吗?我还要争取升教授呢。
===》科学和技术是有不同,没有科学就没有技术,同样,没有技术也谈不上科学

没有物理学没有半导体哪来的avr?
===》非常对,支持一下,这句不是瞎话。所以偶是物理系毕业的,学过四大力学,理论物理、固体物理、半导体物理,还做过半导体物理实验。值得骄傲的是,普通物理和理论物理的期终考试得满分。不过偶不行了,水平太低。真的希望你和你的老师能设计出类似AVR的芯片,省得我们搞技术的老实买外国人的东西。

说“中专”不是贬低你的水平,是说你教的课程是一门应用技术,本科生上和中专生都可以学,作为老师教书育人是没有区别的,
===》哦,明白了。应用技术=中专水平,半导体物理 = 本科水平。你贬低了我关系不大,现在你把应用技术贬低了!
===》我现在就是在教你如何做人。

作为学生,大部分学生也是向中专生看齐的,现在的本科早就不是精英教育了
===》后面这句话我听的进,我在课堂上经常对学生讲我希望精英教育。
===》不过前面你又把很多大学生得罪了。记住:这句话可以你讲的,不要强加在我的头上。

你去中专教书也能培养出色的人才,你能想象去中专教固体物理吗?
===》不清楚你想说明什么。是我教不了中专的固体物理,还是中专生学不了固体物理?

撤退看书去,我手下败将,高兴了?
===》是应该撤退了。胜败不是你评价的。不管胜还是败,我都高兴,因为我不欢迎的人终于要走了
发表于 2011-1-21 20:40:49 | 显示全部楼层
"So? "

here is a simple piece of code, almost identical to yours.

=============code=============

#include <ioavr.h>
//#include <macros.h>
#include <intrinsics.h>                        //we use interrupts

#define NOP()        asm("nop")
#define sei()        __enable_interrupt()

unsigned long tmr1_isr_count=0;

#pragma vector = TIMER1_OVF_vect
__interrupt void tmr1_isr(void) {
        NOP();
        NOP();
        NOP();
        NOP();
        NOP();
        TCNT2+=1;                        //increment tcnt2 - to create a watch condition in proteus
        TCNT1+=100;
        NOP();                                //for debug purposes
}

void tmr1_init(void) {
        TCCR1B =         0;                                                                        //stop the tmr
       
        TCCR1A =        (0 << COM1A1) | (0 << COM1A0) |                //ch a normal port operation
                                (0 << COM1B1) | (0 << COM1B0) |                //ch b normal port operation
                                (0 << COM1C1) | (0 << COM1C0) |                //ch c normal port operation
                                (0 << WGM11) | (0 << WGM10)                        //wgm13..0 = 0b0000 -> normal operation
                                ;
       
        TCCR1B =        (0 << ICNC1) |                                                //input capture noise canceller disabled
                                (0 << ICES1) |                                                //input capture edge select - falling edge
                                (0 << WGM13) | (0 << WGM12) |                //wgm13..0 = 0b0000 -> normal operation
                                (0 << CS12) | (1 << CS11) | (0 << CS10)        //prescaler selection - 0b010 = 1:8
                                ;
       
        TCCR1C =        (0 << FOC1A) |                                                //ch a forced output -> disabled
                                (0 << FOC1B) |                                                //ch b forced output -> disabled
                                (0 << FOC1C)                                                //ch c forced output -> disabled
                                ;
       
        TIMSK1 =        (0 << ICIE1) |                                                //input capture interrupt -> disabled
                                (0 << OCIE1C) |                                                //output compare interrupt on ch c -> disabled
                                (0 << OCIE1B) |                                                //output compare interrupt on ch b -> disabled
                                (0 << OCIE1A) |                                                //output compare interrupt on ch a -> disabled
                                (1 << TOIE1)                                                //tmr overflow interrupt -> enabled
                                ;
       
        TCNT1 = 128;
}

void mcu_init(void) {
}


int main( void )
{
        mcu_init();                        //reset the mcu
        tmr1_init();                //reset the tmr1
        sei();
        while (1) {
        }
       
        return 0;
}
===========end=============

it sets tmr1 to overflow. and in the tmr1 ovf isr, we insert a few NOP(); to inflate the latency.

the watch condition is set on TCNT2 changing. again, TCNT1 is set to increment.

we would expect that due to the NOP(); inserted, the time when we ran into a watch condition will be delayed by 5 cpu cycles, regardless of timer ticks / prescaler (set to be 1:8 now).

the code runs on a 1MIPS usb1286.

here is the time when TCNT2 is stop'd for the 0x10th time. the time is 8.375793s.



(原文件名:usb1286_tmr1 isr latency 1.PNG)
发表于 2011-1-21 20:47:48 | 显示全部楼层
now, we are going to turn off the inserted NOP();. so we expect that our latency is reduced by 5 cpu cycles.



(原文件名:usb1286_tmr1 isr latency 2.PNG)


indeed, the time that tcnt2 is changed 0x10 times is 8.375788s, exactly 5us short than the previous time with the 5 NOP(); inserted in the isr.

you can experiment it more but you will find that regardless of how many times the tmr1 ovf isr is called, whatever the tmr1 prescaler is set, the isr is executed at precisely the same time, as long as you increment / decrement tmr1 counter.
 楼主| 发表于 2011-1-21 20:48:41 | 显示全部楼层
回复【382楼】millwood0

请看371楼的解释,您是否认可?
发表于 2011-1-21 20:52:13 | 显示全部楼层
to further prove that point that you should never assign values to timer/counter and should only increment its values, here is an example where we used "TCNT1=100;", rather than "TCNT1+=100;".


(原文件名:usb1286_tmr1 isr latency 3.PNG)


again, on the 0x10th run of tmr1 isr, the time is considerably longer (and it will be longer in the case of larger isr latency), because by the time you execute "TCNT1=100;", TCNT1 has already has a value in it. By assigning a value to TCNT1, you overwrote that initial value thus lengthen the time it takes to trip each isr.

hope it helps.
发表于 2011-1-21 20:56:12 | 显示全部楼层
"I just want to explain it from the 80X86's point of view. "

it is the same. a pointer is exactly that: a pointer to anything. what a pointer points to has no bearing the type of the pointer. for example, a 32-bit pointer can point to void (0-bit), or a 64k page (64k*8-bit), etc.

that's true regardless of the hardware limitations but subject to hardware limitations.
发表于 2011-1-21 20:57:51 | 显示全部楼层
"millwood0曾说到不要人为的改动计数器,"

I suggest that you re-read what I wrote and try to understand it before trying to dispute it.
 楼主| 发表于 2011-1-21 21:10:59 | 显示全部楼层
because of that, you should never "assign" a value to a timer counter register, after it has been initiated.

instead, you should increment or decrement the timer counter register to maintain timing accuracy.

"TCNT1 = tmr_offset;" for example is the wrong approach.

"TCNT1+= tmr_offset;" is the right approach.

that little "+" operator is incredibly important.
========================================================================

what is the "assign"? "increment" or "decrement" IS also "assign"

you do it that you suggest not to do
 楼主| 发表于 2011-1-21 21:41:45 | 显示全部楼层
回复【353楼】iamseer


(原文件名:Capture2.PNG)


(原文件名:Capture.PNG)


(原文件名:Capture.PNG)

======================================================================
简单帮你算一下。

AVR中断响应需要4个CLK,执行向量中的转移指令3个CLK(这个在考试题中有的),然后还要将标志寄存器压栈,2个CLK;执行5个nop,5个clk. 4+3+2+5 = 14clk。

执行TCNTO += 128,要3条指令:

                               14clk
从TCNT0 取值     1clk          15clk     =====>假如读的是10
加上128          1clk          16clk     =====>此时TCNT0硬件加1了,成为11! 变了!!
回写到TCNT0      1clk                    =====>回写10+128,但正确的应该是11+128, 少了1个计数时钟!

循环10次,少了10个计数时钟,意味者TCNTO要多计10个,1个计数时钟为8个clk,10计数时钟就是80clk,所以时间上超了80clk。

第3个图中,尽管你加了9个NOP,但把TCNT0的硬件加1和TCNT0+=128的执行错开了,因此时钟间隔又与没有NOP的相同了。

哈,这个测试必须是采用硬仿真调试才能获得的,软件模拟好象还不行。
发表于 2011-1-21 23:00:59 | 显示全部楼层
回复【385楼】millwood0  
-----------------------------------------------------------------------

err.... It seems that my proteus agrees with you. I will try it with a real chip an oscilloscope.
发表于 2011-1-21 23:03:13 | 显示全部楼层
测试两种方法:

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

#include <mega16.h>

#define NOP() #asm("nop")
#define LED_Test_Pin PORTD.6

bit Time_1s_Ok;

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
   static unsigned int Time_1s_Count;
   NOP()
   NOP()
   NOP()
   NOP()
   
// Reinitialize Timer 0 value
//TCNT0=0x83;
TCNT0+=0x83;
// Place your code here
   if(++ Time_1s_Count >= 500)  {
       Time_1s_Ok = 1;         
       Time_1s_Count = 0;
   }
}

// Declare your global variables here

void main(void)
{
PORTD=0x00;
DDRD=0x40;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 62.500 kHz
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x03;
TCNT0=0x83;
OCR0=0x00;

TIMSK=0x01;

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

while (1)
      {
      // Place your code here   
         if(Time_1s_Ok){
            Time_1s_Ok = 0;
            LED_Test_Pin = ~LED_Test_Pin;
         }
      };
}

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

Method1: TCNT0 = 0x83; //Directly assign the new value.  Run Once


(原文件名:Method 1.jpg)

Method2: TCNT0 += 0x83; // Use add method to assign the new value. Run Once


(原文件名:Method 2.jpg)

可惜的是使用AVR Dragon仿真时,AVR Studio不能显示执行时间。
发表于 2011-1-21 23:08:46 | 显示全部楼层
手头有AVR Dragon……我实际来试一下吧……
 楼主| 发表于 2011-1-21 23:23:01 | 显示全部楼层
建议你们测试时采用的参数:
系统时钟 1M,1分频。断点设置在TCNT0+=128后面的NOP上,那么每次停下的CLK间隔数为129个,比设置值多1个。
发表于 2011-1-21 23:24:30 | 显示全部楼层
AVR Dragon + AVR 开发板 + iamseer 的测试代码,上图!

方法一:对TCNT0直接操作——TCNT0 = 128;


(原文件名:Dragon Method 1.jpg)

方法二:对TCNT0执行+操作——TCNT0 += 128;


(原文件名:Dragon Method 2.jpg)
发表于 2011-1-21 23:35:31 | 显示全部楼层
没有用Nop的时候~

Method 2: TCNT0 += 128;


(原文件名:Dragon Method 2――2.jpg)
发表于 2011-1-21 23:55:42 | 显示全部楼层
讨论的很精彩啊。有空自己也练习练习。呵呵。
发表于 2011-1-22 00:13:02 | 显示全部楼层
machao

   millwood0 始终在这个问题上想不开,我和他也讨论过这个问题,我连用51都是尽量用自动装载,不行的话也要调整晶振是13,或16位的溢出满足定时要求,最次也要保证低8位要自动归零,然后尽快只调整高8位的计数值.
 楼主| 发表于 2011-1-22 00:25:55 | 显示全部楼层
如果熟悉AVR的指令,就没有必要浪费时间了。从原理上分析就能得到正确的判断。

1。执行中断服务时,计数器一直在工作的。
2。AVR的所有的算术运算指令只能对32个工作寄存器操作。
3。TCNT0寄存器在I/O空间,所以不能直接进行加操作。
4。所以需要先读出TCNT0的值到32个工作寄存器中,然后做加法。再回写到TCNT0中,至少3条指令。
    ; 0000 0017   TCNT0 += 0x05;
  IN   R30,0x32          ;==》这里读TCNT0
  SUBI R30,-LOW(5)       ;==》加5,注意TCNT0已经又自动加上1了!
  OUT  0x32,R30          ;==》回写的是老的TCNT0+5的值,不是上面新的TCNT0+5的值!

哇塞,都是牛脾气。

更容易说明问题的测试是采用16位定时器,调试中看汇编代码,看2次中断的间隔是否是你设定的中断间隔,在中断中任何一句指令上暂停都可以,加几个NOP都没有关系的,正确的应该测两次中断到同一个地方时的间隔是否是你设定的中断间隔。
发表于 2011-1-22 00:29:45 | 显示全部楼层
实际电路与AVR studio保持一致,与proteus不同。

        asm("nop");
        asm("nop");
        asm("nop");
        asm("nop");
        asm("nop");
        TCNT0+=250;
        asm("nop");
        PORTB^=(1<<PB4);

看门狗时钟。一开始忘记去掉8分频了,结果因为dragon在100Hz下每次连接只能正常通讯一次,就锁了,只好看help脚位插线高压救回。不知道128K再八分频还能不能用龙救回。。。。


(原文件名:DSC02510.JPG)


(原文件名:DSC02516.JPG)
友情提示:标题不合格、重复发帖,将会被封锁ID。详情请参考:论坛通告:封锁ID、获得注册邀请码、恢复被封ID、投诉必读
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|阿莫电子论坛(原ourAVR/ourDEV) ( 公安备案:44190002001997(交互式论坛) 工信部备案:粤ICP备09047143号 )

GMT+8, 2019-9-18 04:02

阿莫电子论坛, 原"中国电子开发网"

© 2004-2018 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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