tag 标签: c51

相关帖子
相关博文
  • 热度 17
    2015-12-9 23:52
    2138 次阅读|
    2 个评论
    写在前面:转载请注明出处,如果对您有帮助,请您点个赞。 这是我13年上大学时候上单片机课写的一个题目,是: 按一次按,一个灯亮2秒(另外一个不亮),同时发送1到电脑端;同一个键按两次,刚才亮的现在暗,另外一颗亮4秒。同时发送2。 废话少说,程序如下: #include #define uint unsigned int #define uchar unsigned char sbit key1=P3^4; sbit ledb=P1^0; sbit ledg=P1^1; uint num,num1,num2; int i,j; uchar code table ={'1','2'}; //先把要发送的东西向定义。记住这个格式。 uchar code 。。。 void inti() { TMOD=0x21; //这里对TMOD赋值 用定时器计数器一的方式2,自动重装 TH0=(65536-50000)/256; TL0=(65536-50000)%256; TH1=0xfd;// TL1=0xfd;// 这两句诗程序的难点;这需要数据计算,在波特率为9600bit/s 的情况下,初值为0xfd,这需要记住。 ledb=1; ledg=1; EA=1; ET0=1; ET1=1;//在这个程序中,实际上中断不起作用。所以也不写中断函数。 SCON=0xd8;//记住就行 PCON=0x00;//同上 TR1=1;//同上 } void delay(uint x)//延迟函数 { uint a,b; 0;a--) 0;b--); } void keyscan() { if(key1==0) { delay(10); if(key1==0) { num=1;//标志位! while(!key1); 0;i--) 0;j--)//这两句的意思是在200ms的时间内,检测有没有键按下。 { if(key1==0) { delay(10); if(key1==0) { num=2;//标志位! while(!key1); } } } } } } void Time0() interrupt 1 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; num1++; if(num1==40&&num2==1)//当时间走了两秒且num2为1时 { ledb=1; num1=0; TR0=0; } if(num1==80&&num2==2)//当时间走了4秒且num2为2时 { ledg=1; num1=0; TR0=0; } } void main() { inti(); while(1) { keyscan(); if(num==1) { ledb=0; ledg=1; num2=1;//num2在中断函数中体现作用 TR0=1;//打开计数器 num=0; SBUF=table ;//一下的三句是特定结构 while(TI==0); TI=0; } if(num==2) { ledg=0; ledb=1; TR0=1; num2=2;//num2在中断函数中体现作用 num=0; SBUF=table ; while(!TI); TI=0; } } } 然后,我再重点讲一下 在stc烧写软件下打开窗口助手,然后在串口助手下打开串口(在窗口下方),打开之后会有不同的地方。其他的看图就可以。 ps: 这个刚才看到:定时和计数器的功能区别。 单片机的定时器是用内部时钟信号,计脉冲的个数, 计数器是计外面的脉冲个数, 定时器用的脉冲频率是晶振频率的1/12.当计数个数达到一定值后,产生溢出,产生一个中断信号. 而计数器用的脉冲外面的脉冲,从IO输入,当计数个数达到一定值后,产生溢出,产生一个中断信号. 两者工作原理差不多.都是计数 ,用的信号来源不同.
  • 热度 11
    2015-12-9 16:11
    1222 次阅读|
    0 个评论
    写在之前:转载请注明出处,如果给您帮助,请您点个赞。 和上文一样,是我大学13年是上单片机的习题,拿出来看看有没有帮助到需要的人 。与上文要相互联系。 #include #define uint unsigned int sbit key1=P3^4; sbit ledb=P1^0; sbit ledg=P1^1; uint num,num1,num2; void inti() { TMOD=0x11; TH0=(65536-50000)/256; TL0=(65536-50000)%256; TH1=(65536-50000)/256; TL1=(65536-50000)%256; ledb=0; ledg=0; } void delay(uint x) { uint a,b; 0;a--) 0;b--); } void keyscan() { if(key1==0) { delay(10); if(key1==0) { num++; if(num==1) { EA=1; ET0=1; TR0=1; num=0; while(!key1); } if(num==2) { EA=1; ET1=1; TR1=1; num=0; while(!key1); } //难点 } } } void Time0() interrupt 1 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; num1++; if(num1==40) { ledg=1; ledb=0; } if(num1==120) { ledg=1; ledb=1; num1=0; TR0=0; } } void Time1() interrupt 3 { TH1=(65536-50000)/256; TL1=(65536-50000)%256; num2++; ledg=1; ledb=0; if(num2==120) { ledg=1; ledb=1; num2=0; TR1=0; } } void main() { inti(); while(1) { keyscan(); } } 上面这条程序的意思是你按同一个键一次,灯亮2秒后停息,按两次,灯亮六秒后停止。 上面是用两个定时器的。 用一个定时器和计数器来解决程序。 程序改动如下: #include #define uint unsigned int sbit key1=P3^4; sbit ledb=P1^0; sbit ledg=P1^1; uint num,num1,num2; void inti() { TMOD=0x01; TH0=(65536-50000)/256; TL0=(65536-50000)%256; //TH1=(65536-50000)/256; //TL1=(65536-50000)%256; ledb=1; ledg=1; EA=1; ET0=1; } void delay(uint x) { uint a,b; 0;a--) 0;b--); } void keyscan() { if(key1==0) { delay(10); if(key1==0) { num++; if(num==1) { TR0=1; num=0; num2=1; while(!key1); } if(num==2) { TR0=1; num=0; num2=2; while(!key1); } } } } void Time0() interrupt 1 { TH0=(65536-50000)/256; TL0=(65536-50000)%256; if(num2==1) { ledb=0; num1++; if(num1==40) { ledb=1; TR0=0; num2=0; num1=0; } } if(num2==2) { ledg=0; num1++; if(num1==20) { ledg=1; TR0=0; num2=0; num1=0; } } } void main() { inti(); while(1) { keyscan(); } }
  • 热度 32
    2015-9-6 18:12
    2038 次阅读|
    0 个评论
    Keil C51总线外设操作问题的深入分析 1问题回顾和分析 在实际工作中遇到对同一端口反复连续读取,Keil C51编译并未达到预期的结果。对C编译出来的汇编程序进行分析发现,对同一端口的第二次读取语句并未被编译。 对此问题,翻阅Keil C51的手册很容易发现:KeilC51的编译器有一个优化设置,不同的优化设置,会产生不同的编译结果。一般情况缺省编译优化设置被设定为8级优化,实际最高可设定为9级优化: 1. Dead code elimination。 2.Data overlaying。 3.Peephole optimization。 4.Register variables。 5.Common subexpression elimination。 6.Loop rotation。 7.Extended Index Access Optimizing。 8.Reuse Common Entry Code。 9.Common Block Subroutines。 而以上的问题,正是由于Keil C51编译优化产生的。因为在原文程序中将外设地址直接按如下定义: unsigned char xdata MAX197 _at_ 0x8000 采用_at_将变量MAX197定义到外部扩展RAM指定地址0x8000。因此,Keil C51优化编译理所当然认为重复读第二次是没有用的,直接用第一次读取的结果就可以了,因此编译器跳过了第二条读取语句。至此,问题就一目了然了。 2解决方法 由以上分析很容易就能提出很好的解决办法。 2.1最简单最直接的办法 程序一点都不用修改,将Keil C51的编译优化选择设置为0(不优化)就可以了。选择project窗口的Target,然后打开“Options for Target”设置对话框,选择“C51”选项卡,将“Code Optimiztaion”中的“Level”选择为“0:Costant folding”。再次编译后,大家会发现编译结果为: CLR MAXHBEN MOV DPTR,#MAX197 MOVX A,@DPTR MOV R7,A MOV down8,R7 SETB MAXHBEN MOV DPTR,#MAX197 MOVX A,@DPTR MOV R7,A MOV up4,R7 两次读取操作都被编译出来了。 2.2最好的方法 告诉Keil C51,这个地址不是一般的扩展RAM,而是连接的设备,具有“挥发”特性,每次读取都是有意义的。可以修改变量定义,增加“volatile”关键字说明其特征: unsigned char volatile xdata MAX197 _at_ 0x8000; 也可以在程序中包含系统头文件;“#includeabsacc.h”,然后在程序中修改变量,定义为直接地址: #define MAX197 XBYTE 这样,Keil C51的设置仍然可以保留高级优化,且编译结果中,同样两次读取并不会被优化跳过。 2 .3硬件解决方法 原文中将MAX197的数据直接连接到数据总线,而对地址总线并未使用,采用一根端口线选择操作高低字节。很简单的修改方法就是使用一根地址线选择操作高低字节即可。比如:将P2.0(A8)连接到原来P1.0连接的HBEN脚(MAX197的5脚).在程序中分别定义高低字节的操作地址: unsigned char volatile xdata MAX197_L _at_ 0x8000; unsigned char volatile xdata MAX197_H _at_ 0x8100; 将原来的程序: MAXHBEN =0; down8=MAX197;//读取低8位 MAXHBEN =1; up4=MAX197;//读取高4位 改为以下两句即可 down8= MAX197_L;//读取低8位 up4=MAX197_H;//读取高4位 3小结 Keil C51经过长期考验和改进以及大量开发人员的实际使用,已经克服了绝大多数的问题,并且其编译效率也非常高。对于一般的使用.很难再发现什么问题。笔者曾经粗略研究过一下Keil C51优化编洋的结果.非常佩服Keil C51设计者的智慧,一些C程序编译产生的汇编代码.甚至比一般程序员直接用汇编编写的代码还要优秀和简练通过研读Kell C51编译产生的汇编代码.对提高汇编语言编写程序的水平都是很有帮助的。 由本文中的问题可以看出:在设计中遇到问题时.一定不要被表面现象蒙蔽,不要急于解决,应该认真分析,找出问题的原因.这样才能从根本上彻底解决问题。 转自畅学电子网。
  • 热度 19
    2013-9-29 13:36
    1673 次阅读|
    2 个评论
      Keil 中 C 和汇编混合编程   本文主要参考网上的文章,再进行实践操作整理而成,如有相似之处实属抱歉!在实际应用中有可能基于运行速度的要求可能会在C程序中调用汇编程序,一般不会在汇编程序中调用C程序!不同的编译器具体不同的调用方式,主要取决于编译器本身。下面就说说在Keil C51中怎样实现C程序中调用汇编程序。   在C程序中调用汇编程序一般有两种方法:   1. 直接使用编译器提供的参数块   #pragma asm AsmCode…… #pragma endasm   a.       对工程进行如下设置: b.       根据Memory Model的选择包含相关的.Lib文件,如当是SMALL模式时包含C51S.LIB。将此文件放入此工程目录下并进行编译链接。网上说一定要放在最后在进行编译才行,经过实验与所放位置无关,可能是编译器版本原因。   2. 在C 程序中调用汇编函数块   这种情况下又可分为两种形式,一种是带有形参的调用,一种是不带形参的调用,前者相对后者复杂,其实两者不同在于对于参数的保存与调用。   2.1 在C 程序中调用不带形参的汇编函数   大致思想与C中相差不大,就是在调用文件中先对将调用的汇编函数进行外部声明,再在.a51文件中编写函数的内容,只不过由于要从C过渡到汇编并且要让编译器知道你在做什么所以有些规则就要遵守编译器。下面说说基于Keil4与SI1000的例子:   如我们想调用汇编函数:void asmFun(void),可分为如下几个步骤:   a.       先在源C文件中先定义这个函数,但是不要编写里面的函数体,仅仅是定义而已,然后选择此c源文件的属性让其生成.src文件如下 这一步的主要目的是要查看生成的.src汇编文件中asmFun函数的信息,好让我们复制到函数的定义asmFun.a51文件中(这步做完后要将源C文件中的函数定义删除,以及上面的设置也要恢复到原来的状态)。 b.       建立新的汇编源文件*.A51。里面主要包含void asmFun(void)的函数体内容。本例中由于使用的是非常规51内核所以在.A51文件中首先在包含该硬件的头文件如$INCLUDE (REG51Si1000.h),此处要用括号,不然找不到此文件的合法路径,即使用绝对路径也找不到,不知为何!包含此文件后一定要对工程进行如下设置: 否则编译器会说你企图重复定义有关的SFR,其实当你找遍整个工程时你都不会发现你有重复定义的问题,问题在于编译器默认情况下就事先已经将传统的基本51内核SFR寄存器做了定义,所以当然它会说你是错的!于是接下来的代码如下(是关于串口设置的),都是从.src文件中复制过来,具体细节不细说,主要是跟编译器有关,自己也有点不是很清楚,主要是查看编译器手册:   ?PR?asmFun1?DEMO11 SEGMENT CODE PUBLIC  asmFun RSEG  ?PR?asmFun?DEMO11   asmFun: CLR      EA MOV     SCON0,#010H SETB     ES0 SETB     EA RET END c.在C源文件中进行调用。调用之前要先进行外部声明extern void asmFun(void),然后直接调用即可!上述就是不带参数的汇编函数调用,具体过程见附件:   2.2 在C 程序中调用带形参的汇编函数   在C程序中调用带形参的汇编函数网上有的说的很复杂比较难懂,我就说说很简单的吧!一般C函数的形参翻译成汇编语言后会存储在特定的寄存器与特定的内存中,一般情况下如果函数的形参三个会存储在寄存器中,其它的会存储在特定的内存中,如有特殊情况也会都存储在相关内存中。参数的具体分配如下:   关于内存区分配的形参还不是很明白,暂且不说了,反正就是如果你想在汇编程序中使用相关的形参就直接调用这个形参所存储的寄存器即可,其实和不带形参的方式基本上一样!大致就先说这么多了,还有很多的细节部分需要注意,这要等以后运用的过程中发现问题,然后再解决问题!Keil中有部分解释但不是很清楚,请参阅Keil/hlp/Cx51 Compiler User’s Guide,除非特殊需要否则还是不建议C中调用汇编的做法,因为有点麻烦,大多要依靠编译器本身的特性,容易出错!   网上参考文献:http://hnllei.blog.163.com/blog/static/142039242201142711550874/ 怎么有时插图总是插不上啊!
  • 热度 33
    2011-6-3 17:44
    5368 次阅读|
    13 个评论
    这是一款自己开发的视频音频输入输出自动切换的控制板!它采用S52为单片机。12846做中文显示!可实现1路视频和音频输入,4路视频和4路音频的单路通道轮流输出和四路视频音频通道的同时输出功能!可切换对讲LINE IN ,支持串口与PC通讯!同时可将所有的视频切换信息随时随地通过串口传给电脑,电脑可通过软件接收信息存到服务器中保存!以备查询!在切换的同时LED灯实时显示目前的通道数!12864也以中文的方式显示目前正处在哪个通道!以方便巡查!   该控制板还可以控制24V电压的输入!以方便控制大电器的开关!   开发这款控制板的目的是为了测试视频通道和音频通道的单独输入自动化检测,比如多路DVR,视频服务器或者是多路监视器,或者是其他多路视频音频设备的检测!提高检测输入,实现防呆(防漏检),防错检,智能化测试的提高!为公司或为检测机构提高 了效率!如果大批量检测更能体现出这款产品的实用性!   从技术上将,开发这款产品着重在于芯片的选择,对于视频放大,视频选通等功能的芯片选择上需要满足芯片的高带宽,高频率的要求。   现发此资料以供大家分享!谢谢支持     电路原理图截图!   PCB设计图截图   PCB板正面截图   PCB板反面截图 感谢支持!未完待续……            
相关资源