Keil下初次玩AT89C51,被定时器搞吐血了!特来求救!

KiteGirl 2008-01-14 03:50:15
原本用循环延时,见下帖子:
http://topic.csdn.net/u/20080113/22/a42c9278-e38d-4d0f-af0b-b7834b301f40.html

后来发现C编译后的循环不是精确到时钟周期的。于是改用定时器(代码如下)。
据说89C51定时器是1/12分频的,应该是1us一个记数,1ms理应是1000次记数(定时器初始值65536-1000=64536)。
可实际把程序写出来Keil下仿真发现明显过快。后来把中断记数周期改成12000次,才够1ms,彻底吐血。
由于手头没有仿真器和单片机,程序只在Keil下软件仿真,实在不知道究竟怎么回事,特来求救。
谁能帮我搞清楚这个问题,此帖及上面那帖子总共200分全给他。最好哪位老兄有单片机实际帮我测试一下。
此程序应该是以500ms的间隔依次点亮连接在P1、P2的16盏灯。


#include <C:\Keil51\C51\INC\REG51.h>

//
unsigned int pubTimerInt;
unsigned int pubTimerValue;

void SetTimerout(unsigned int pTimeout)
{
EA=1;
ET0=1;
TMOD=0x01;
pubTimerValue=65535-pTimeout;
TH0=pubTimerValue/256;
TL0=pubTimerValue%256;
TR0=1;
}

void intserv1(void) interrupt 1 using 1
{
if (pubTimerInt>0)
{
pubTimerInt=pubTimerInt-1;
}
TH0=pubTimerValue/256;
TL0=pubTimerValue%256;
}

void WhileTimeout(unsigned int pTimeout)
//WhileTimeout函数
//语法:WhileTimeout(pTimeout);
//说明:产生pTimeout指定延时,单位为ms。
//参数:unsigned int pTimeout 单位为ms的延时参数。
{
TR0=1;
TH0=pubTimerValue/256;
TL0=pubTimerValue%256;
pubTimerInt=pTimeout;
TR0=1;
while(pubTimerInt)
{
}
}

void ProtDevice_LO(unsigned char pConByte, unsigned char pProt)
//ProtDevice函数
//语法:ProtDevice(pConByte, pProt);
//说明:驱动端口(低电平开启)。
//参数:unsigned char pConByte 端口控制字节(高电平开启)。
// unsigned char pProt 端口选择(0-3)
{
switch(pProt)
{
case 0: P0=~pConByte;break;
case 1: P1=~pConByte;break;
case 2: P2=~pConByte;break;
case 3: P3=~pConByte;break;
}
}

void LoopOpen_LO(unsigned int pOpenTimeout, unsigned char pProt)
//LoopOpen_LO函数
//语法:LoopOpen_LO(pOpenTimeout, pProt);
//说明:循环驱动端口(低电平开启)。
//参数:unsigned int pOpenTimeout 开启时间设置(单位ms)
// unsigned char pProt 端口选择(0-3)
{
unsigned char tConByte;
unsigned int tLoopIndex;
unsigned int tLoopIndex_Length;

tLoopIndex_Length=7;

//开关0号。
tConByte=1;
ProtDevice_LO(tConByte, pProt); //驱动端口
WhileTimeout(pOpenTimeout);

//开关1-7号。
for (tLoopIndex=0; tLoopIndex<tLoopIndex_Length; tLoopIndex++)
{
tConByte=tConByte<<1;
ProtDevice_LO(tConByte, pProt); //驱动端口
WhileTimeout(pOpenTimeout);
}
}

void main()
{

unsigned char tProtA;
unsigned char tProtB;
unsigned char tConByte;
unsigned int tOpenTimeout;
unsigned int tWhileTimeout;
unsigned int tTimeoutValue;
tProtA=1;
tProtB=2;
tOpenTimeout=500;
tWhileTimeout=3000;
tTimeoutValue=12000; //按道理应该是1000us=1ms,可这里一定要设置12000才能保证中断是1ms。
tConByte=0;
ProtDevice_LO(tConByte, tProtA);
ProtDevice_LO(tConByte, tProtB);
SetTimerout(tTimeoutValue);
while(1)
{
//第一端口
LoopOpen_LO(tOpenTimeout, tProtA);
tConByte=0;
ProtDevice_LO(tConByte, tProtA);
//第二端口
LoopOpen_LO(tOpenTimeout, tProtB);
tConByte=0;
ProtDevice_LO(tConByte, tProtB);
//等待
WhileTimeout(tWhileTimeout);
}
}


编译后的HEX文件内容:

:1000E200D2AFD2A9758901C374FF9FF51274FF9E26
:0A00F200F511F58C85128AD28C22DC
:03000B0002009D53
:10009D00C0E0C0D0D3E5149400E51394004008E50A
:1000AD0014151470021513E511F58C85128AD0D034
:0300BD00D0E0325E
:1000FC00AD07AC06D28CE511F58C85128A8C138D6C
:0A010C0014D28CE514451370FA229A
:1000C000ED14600F14601114601324037013EFF427
:1000D000F58022EFF4F59022EFF4F5A022EFF4F58D
:0200E000B0224C
:060062008D0EAB07AA069B
:10006800750F0075100779017F011200C0AF0312E8
:1000780000FC900000C3E5829510E583950F5014AD
:10008800E925E0F9FFAD0E1200C0AF03AE02120081
:04009800FCA380E164
:01009C002241
:10000E00750801750902750A01750BF4750C0B75EF
:10001E000DB87BE07A2EE4F9FFAD081200C0AD09F1
:10002E001200C07FE07E2E1200E2AD08AF0BAE0ACA
:10003E00120062E4F9FFAD081200C0AD09AF0BAEBD
:10004E000A120062E4FFAD091200C0AF0DAE0C1231
:04005E0000FC80D64C
:03000000020116E4
:0C011600787FE4F6D8FD75811402000E1D
:00000001FF
...全文
898 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhujinqiang 2008-01-23
  • 打赏
  • 举报
回复
哦也!

KiteGirl 2008-01-22
  • 打赏
  • 举报
回复
好了!解决了。另外一个帖子我等等yanglin5131421去接分,如果他不接的话三天之内我会结的。:)

我讨厌被人用枪指着后脑勺结帖子!!!>(
MBWQ 2008-01-22
  • 打赏
  • 举报
回复
哈哈!今天我用面包板把单片机搭出来了,实验成功了!果然烧到AT89C51上是0.5s,而不是仿真时候那么快。

感谢MBWQ、zhujinqiang、yanglin5131421三位。请你们同时到下面帖子里接另外的100分。

http://topic.csdn.net/u/20080113/22/a42c9278-e38d-4d0f-af0b-b7834b301f40.html


----------------------------------------------------------------------------------------
言必行,行必果,请楼主及时结贴
lbing7 2008-01-22
  • 打赏
  • 举报
回复
哈哈哈哈哈

小仙妹怎么说也是水源一大镁铝哈

嘿嘿嘿

KiteGirl 2008-01-22
  • 打赏
  • 举报
回复
不会结贴?
呵呵,

方法:
管理帖子--> 输入密码(1楼右上角)--> 给各人分--> 结贴(1楼右上角)
=====================================================================
没搞错吧!我会这么弱智吗?想催我结贴就明说嘛……:)
zhujinqiang 2008-01-22
  • 打赏
  • 举报
回复
不会结贴?
呵呵,

方法:
管理帖子--> 输入密码(1楼右上角)--> 给各人分--> 结贴(1楼右上角)
KiteGirl 2008-01-14
  • 打赏
  • 举报
回复
TF0响应后自动清0的,因此在中断处理程序里TF0总是0。加上TF0=0还是一样飞快。
我手头没有仿真器和单片机,所以上述结果是在Keil里测试发现的。还不知道真正烧到片里什么样子。
计数器周期从1000改成12000是我猜的(因为我感觉它的速度是12倍),于是我把计数器周期改成12000之后,将定时脉冲从500改成1000,发现刚好是一秒。也就是说12000次计数才是1秒。似乎压根就没有1/12分频。彻底精神崩溃了。
zhujinqiang 2008-01-14
  • 打赏
  • 举报
回复
晕,是TF0=0
zhujinqiang 2008-01-14
  • 打赏
  • 举报
回复
void intserv1(void) interrupt 1 using 1
{
if (pubTimerInt>0)
{
pubTimerInt=pubTimerInt-1;
}
TH0=pubTimerValue/256;
TL0=pubTimerValue%256;
TF01=0; /*漏了这个--计数溢出标志位清0*/
}
zhujinqiang 2008-01-14
  • 打赏
  • 举报
回复
80C51单片机的1个机器周期有12个振荡周期组成。12MHZ,它的时钟周期是1/12us。

当80C5l内部的定时器/计数器被选定为定时器工作模式时,计数输入信号是内部时钟脉冲,每个机器周期产生一个脉冲位,计数器增l,因此定时器/计数器的输入脉冲的周期与机器周期一样,为时钟振荡频率的l/12。当采用12MHz频率的晶体时,计数速率为 1MHz,输入脉冲的周期间隔为1us。

void SetTimerout(unsigned int pTimeout)
{
EA=1;
ET0=1; /*设置T0为定时方式1*/
TMOD=0x01;
pubTimerValue=65535-pTimeout;
TH0=pubTimerValue/256;
TL0=pubTimerValue%256;
TR0=1;
}
/*上面正常。*/
void intserv1(void) interrupt 1 using 1
{
if (pubTimerInt>0)
{
pubTimerInt=pubTimerInt-1;
}
TH0=pubTimerValue/256;
TL0=pubTimerValue%256;

TF1=0; /*计数溢出标志位清0*,这个漏了!/
}


yanglin5131421 2008-01-14
  • 打赏
  • 举报
回复

LZ来看看我前几天转载的一个帖子,希望对你有帮助
http://topic.csdn.net/u/20080110/11/6be2a051-b997-4d78-a9bd-3957fdf86414.html
yanglin5131421 2008-01-14
  • 打赏
  • 举报
回复

LZ来看看我前几天转载的一个帖子,希望对你有帮助
http://topic.csdn.net/u/20080110/11/6be2a051-b997-4d78-a9bd-3957fdf86414.html
KiteGirl 2008-01-14
  • 打赏
  • 举报
回复
哈哈!今天我用面包板把单片机搭出来了,实验成功了!果然烧到AT89C51上是0.5s,而不是仿真时候那么快。

感谢MBWQ、zhujinqiang、yanglin5131421三位。请你们同时到下面帖子里接另外的100分。

http://topic.csdn.net/u/20080113/22/a42c9278-e38d-4d0f-af0b-b7834b301f40.html
yanglin5131421 2008-01-14
  • 打赏
  • 举报
回复
呵呵,小仙妹 您好,你是搞单片机的吗?总在水源听说您的大名,从来为得一见,呵呵
zhujinqiang 2008-01-14
  • 打赏
  • 举报
回复
晶体频率注意看看。
zhujinqiang 2008-01-14
  • 打赏
  • 举报
回复
有处理中断的时间在内,
所以实际计数值是调整的。

中断记数周期改成12000次,才够1ms,那么就用12000。
KiteGirl 2008-01-14
  • 打赏
  • 举报
回复
我选的是AT89C51。
zhujinqiang 2008-01-14
  • 打赏
  • 举报
回复
AT89LP2052,AT89LP4052就是单周期高速低功耗51内核单片机
zhujinqiang 2008-01-14
  • 打赏
  • 举报
回复
keil仿真,keil里面选的什么类型的芯片?
有的厂家的51的是单周期的。
KiteGirl 2008-01-14
  • 打赏
  • 举报
回复
根你试验了,你的程序没问题,是keil仿真出了问题
===========================================
试验的时候main函数的tTimeoutValue=12000是否改成了tTimeoutValue=1000呢?
我自己编译的HEX是12000的设置,这在仿真时是正常的,但理论上不对。
应当改成1000后保持0.5s滚动才对。

不过现在看来keil仿真的速度真的有点不大对头。
加载更多回复(2)
内容概要:本文系统整理了《微软面试100题完整版(含解析+备考指南)2026最新求职资源》,涵盖算法编程、逻辑思维、计算机基础、系统设计与工程实践、职场综合五大核心题型,共100道高频原题,均来自微软近十年真实面试题库,剔除过时内容,新增AI工程应用、轻量化系统设计等2026年前沿考点。每道题目配有详细解题思路与考察要点,覆盖数据结构、动态规划、位运算、网络协议、数据库事务、微服务架构、高并发设计等关键技术领域,并包含逻辑推理、工程排查、产品权衡等综合素质题目,全面适配微软海内外各岗位面试需求。此外,文章还提供分层刷题策略、地域差异化备考建议及完整资源获取路径,助力求职者高效通关初面、复面与终面。; 适合人群:准备应聘微软的应届毕业生、1-5年工作经验的技术岗从业者(如软件开发、算法、测试、数据、运维等),以及计划投递微软海外岗位的求职者;尤其适合缺乏系统面试准备、希望提升解题思维与工程表达能力的人群。; 使用场景及目标:①针对微软技术面试中的算法题进行专项突破,掌握最优解法与代码规范;②训练逻辑思维与系统设计能力,应对高阶岗位考察;③准备终面综合问题,提升职场素养与岗位匹配度表达;④根据国内/海外不同考点调整复习重点,实现精准备考。; 阅读建议:此资源以真题为核心,强调解题思路而非死记硬背,建议按“分类刷题—总结模板—模拟手撕—复盘优化”流程学习,重点关注代码边界处理、复杂度优化与中英文表达逻辑,结合自身背景补充项目复盘与系统设计练习,全面提升面试实战能力。
内容概要:本文围绕永磁同步电机(PMSM)的二阶线性自抗扰矢量控制系统展开深入研究,重点实现了基于Simulink的系统建模仿真。研究采用二阶线性自抗扰控制(LADRC)策略,结合扩张状态观测器(ESO)对系统内部动态和外部扰动进行实时估计与前馈补偿,有效提升了电机在负载突变、参数摄动等复杂工况下的转速控制精度、动态响应速度与系统鲁棒性。文中详细构建了电流环与转速环的双闭环矢量控制架构,系统分析了控制器关键参数的设计方法、观测器带宽的整定原则以及整体系统的稳定性条件,并通过大量仿真实验验证了所提出控制方案相较于传统PI控制在抗干扰能力、响应性能和鲁棒性方面的显著优越性。; 适合人群:具备自动控制理论、电机控制原理、现代控制理论等相关专业知识,熟悉Simulink/Matlab仿真环境,且有一定工程实践经验的电气工程、自动化、控制科学与工程等领域的硕士/博士研究生、科研人员及从事高性能电机驱动系统开发的工程技术人员。; 使用场景及目标:①为高等院校和科研机构提供先进电机控制算法的教学案例与科研实验平台,深化对自抗扰控制(ADRC)理论的理解;②为企业在高性能伺服驱动、新能源汽车电驱系统、工业自动化等领域的下一代控制器研发提供可靠的技术参考、仿真验证方案和原型设计基础;③帮助研究人员系统掌握ADRC的核心思想、设计流程及其在高精度运动控制系统中的具体工程实现方法。; 阅读建议:学习者应具备扎实的自动控制与电机学理论基础及Simulink建模能力,建议结合韩京清教授的经典ADRC文献进行原理性学习,深入理解ESO的观测机理与TD的安排机制。在仿真实践中,应动手调试控制器带宽、观测器增益等核心参数,对比分析不同扰动工况(如突加负载、转速指令跳变)下的系统响应曲线,以直观感受控制性能的差异。为进一步深化研究,可将该仿真模型与硬件在环(HIL)测试平台或实际电机实验平台对接,完成从算法设计、仿真验证到物理实现的完整闭环验证流程。

27,521

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 单片机/工控
社区管理员
  • 单片机/工控社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧