打印
[AVR单片机]

考考你:单片机C编程中的注意点

[复制链接]
2860|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
winsu|  楼主 | 2007-6-28 10:47 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
考考你:单片机C编程中的注意点

如果你是高手,则可能不会遇上这样的小问题,所以你就不用浪费时间来看下面贴子了。
以下是用定时器等待端口状态的二个函数,等待某端口低电平,若超时则返回。
请看完程序后,选择一个你认为较好或正确的程序,并说明原因。
硬件环境:M8,8MHz
程序1:
u8 test_delay_1(u8 bit)
{
    //设置16位计数器(T/C1)为普通模式
    TCCR1A = 0x00;
    //预分频,0x02=0000010,8分频,最大延时约65ms,
    TCNT1 = 0xFFFF - 10000;    //可调节延时时间
    TCCR1B = 0x02;
    do
    {
        if((TEST_PIN & (1<<bit)) == 0)         //等待端口为低电平
        {
            TCCR1B = 0x00;
            return !0;
        }
    }while(TCNT1);
    //停止计时器
    TCCR1B = 0x00;
    return 0;            //超时返回
}

程序2:
u8 test_delay_2(u8 bit)
{
    //设置16位计数器(T/C1)为普通模式
    TCCR1A = 0x00;
    //预分频,0x02=0000010,8分频,最大延时约65ms,
    TCNT1 = 0;
    TCCR1B = 0x02;
    do
    {
        if((TEST_PIN & (1<<bit)) == 0)         //等待端口为低电平
        {
            TCCR1B = 0x00;
            return !0;
        }
    }while(TCNT1 < 10000);    //可调节延时时间
    //停止计时器
    TCCR1B = 0x00;
    return 0;            //超时返回
}

相关帖子

沙发
eqtwo| | 2007-6-28 16:08 | 只看该作者

程序2:ok

程序1: while(TCNT1);有可能错过TCNT1 == 0 这个机会跳出 ;
本人愚见;

使用特权

评论回复
板凳
yewuyi| | 2007-6-29 17:10 | 只看该作者

多字节增减判断的问题?

最好的方法就是用BUF

使用特权

评论回复
地板
NE5532| | 2007-6-30 22:37 | 只看该作者

反正都是死等,何必用定时器。

使用特权

评论回复
5
hotpower| | 2007-7-1 04:01 | 只看该作者

4楼说得有些道理~~~

使用特权

评论回复
6
su_mj000| | 2007-7-1 21:04 | 只看该作者

TCNT1是个双字节变量。

当低字节因递增从0xFF变成0x00时,前台操作可能得到错误值而造成
误动作。

例如:TCNT1由0xFFFF变成0x0000时,前台主程序先读取低字节0xFF,
在读取高字节可能得到0x00。整个16位值就成了0x00FF了。

所以两种方法都有严重的缺陷!尤其是第二种方法。

此类问题的深层原因是数据总线的宽度小于数据宽度。

使用特权

评论回复
7
yewuyi| | 2007-7-2 08:32 | 只看该作者

就事论事,用BUF可以解决问题

改变程序结构,如果不是要求很高时间精度的话,那么用调度器的时间周期计算也可以;
如果要求比较高的时间精度的话,在调度器的时间周期加 一点定时器应用小技巧就OK,这个小技巧俺不能告诉你,免得你使用不当害了你……

使用特权

评论回复
8
winsu|  楼主 | 2007-7-4 09:01 | 只看该作者

为何用定时器

to NE5532 :
这是一个测试用的东东,因等待要较准确的时间,而定时器空闲,所以就用定时器了,虽然有点浪费。
to su_mj000:
这是M8中文规格书中的说明:
注意到16 位寄存器的访问是一个基本操作是非常重要的。在对16 位寄存器操作时,最好首先屏蔽中断响应,防止在主程序读写16 位寄存器的两条指令之间发生这样的中断:它也访问同样的寄存器或其他的16 位寄存器,从而更改了临时寄存器。如果这种情况发生,那么中断返回后临时寄存器中的内容已经改变,造成主程序对16 位寄存器的读写错误。
这个应用中没用到中断
to yewuyi:
对不起,我的系统中没用到“调度器”,这只是个简单的应用而已。

使用特权

评论回复
9
su_mj000| | 2007-7-4 14:02 | 只看该作者

8楼的,既然是个实际应用,

判断中断标志才是最佳方案。

另外,我以为既使关中也无法避免错读。因为关中后,计数器仍在递增计数。
递增可能发生在两次单字节读取之间。

使用特权

评论回复
10
yewuyi| | 2007-7-7 08:22 | 只看该作者

LS提的很对

关中断不是总有效的,但使用BUF肯定都是有效的,增加一个局部变量也很简单,纯软件解决问题,又何必去人为折腾中断标志

使用特权

评论回复
11
NE5532| | 2007-7-7 10:32 | 只看该作者

定时器的时间精度和软件延时是一样的。

最终的振荡来源都是晶体。只要没有其他中断哈。

使用特权

评论回复
12
yujz| | 2007-7-7 11:23 | 只看该作者

回复

AVR对16 位寄存器是一次性读出或写入,其高位(或低位)保存在临时寄存器中,关中后能避免临时寄存器被改写,不会错读了吧.

使用特权

评论回复
13
ayb_ice| | 2007-7-9 15:07 | 只看该作者

随便说说

都有问题,但2要好些...
中断程序会影响while(TCNT1 < 10000);的执行...
应该通过定时中断来通知是否超时,如在中断中设一标志,然后判断标志,最简单就是连续判断N次然后返回...


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

16

主题

64

帖子

0

粉丝