tag 标签: 51单片机

相关帖子
相关博文
  • 热度 2
    2024-2-23 21:30
    442 次阅读|
    0 个评论
    51单片机大学生入门记录【1-1流水灯】
    成果展示----流水灯 代码展示 #include void Delay1ms(unsigned int xms) //@12.000MHz { unsigned char i, j; while(xms) { i = 2; j = 239; do { while (--j); } while (--i); xms--; } } void main() { while(1) { P1=0xFE; Delay1ms(500); P1=0xFD; Delay1ms(500); P1=0xFB; Delay1ms(500); P1=0xF7; Delay1ms(500); P1=0xEF; Delay1ms(500); P1=0xDF; Delay1ms(500); P1=0xBF; Delay1ms(500); P1=0x7F; Delay1ms(500); } } 硬件解析 我们可以看到8颗LED灯分别接在了 P1-P1.7 引脚上面,并且都出串联了限流电阻(起保护作用) P1-P1.7全部都在P1总线上面,所以在代码部分只需要控制P1的"开关"即可控制全部LED灯 并且可以看到,电路采用的是"灌电流"输出,意味着io口相当于接地的作用 所以 LED灯低电平点亮,高电平熄灭 代码解析----点亮一个LED 首先我们需要搞清楚,LED灯在什么时候才能点亮,由上面的硬件解析可以得出,LED灯在P1处于低电平时点亮,处于高电平的时候是熄灭状态 所以p1-p1.7在熄灭时候对应的二进制为 1111 1111 (1为高电平,0为低电平) p1-p1.7全部都位于1高电平,所以全部熄灭 若二进制为 1111 1110 第一位p1为0,其余p1.1-p1.7为1,则p1对应的LED灯亮,因为p1此时为0低电平,其余都为1高电平 所以在代码部分,我们应该写 P1=11111110,但是软件是基于c语言编程的,所以c语言不能识别二进制,所以我们需要把 二进制转换成十六进制 11111110转十六进制就是 FE 所以我们在代码上就应该写FE 因为 是便于解释器的识别, 是十六进制的标志 所以FE前面我们应该把十六进制的前缀加上,则 0xFE 此时上传代码应该可以看到,LED的第一个灯被点亮了 代码解析----循环函数 首先,我们可以在stc-isp里面生成一个1ms的循环函数 然后我们可以自己定义一个函数(xms) 这样我们输入多少,就会循环多少次1ms达到这样一个效果 假如,我xms输入一个500 首先会进行500次循环 每循环一次,函数会自己减去1 则,我输入500,循环一次完成后,就自动变成499次循环 这个函数是软件给我们生成的1ms的循环 如果500次1ms,那就是500ms,相当于0.5秒的循环 所以,我们在main函数里面引用这个延迟函数,然后在延迟函数里面给他定义一个500次 相当于延迟了0.5秒然后跳转到下一步 代码解析----流水灯的循环 我们在知道灯的原理,同时也知道循环的原理之后,就可以做一个相关的流水灯 现在的代码就非常好理解了,在第一个LED灯亮了之后,然后延迟500ms,自动跳到下一个灯,以此类推,一直循环下去 这里再细细讲解一下 第一个灯,对应的二进制为1111 1110 【FE】 第二个灯,对应的二进制为1111 1101 【FD】 第三个灯,对应的二进制为1111 1011 【FB】 。。。以此类推 所以到最后一个灯就应该是 0111 1111 【7E】 总结 51单片机对于新手来说还是比较友好的,基本上懂了LED点亮的原理,以及二进制转换十六进制的方法之后,这个项目就非常容易做了! 而且要理解一下循环函数的原理。简单来说如果我要定时500ms,其实相当于是把1ms循环了500遍这样 最后,祝大家学有所用!
  • 热度 18
    2015-12-21 18:14
    894 次阅读|
    0 个评论
    1、理论知识   PWM这个功能在飞思卡尔、STM32等高档的单片机内部有专用的模块,用此类芯片实现PWM功能时只需要通过设置相应的寄存器就可实现周期和占空比的控制。但是如果要用51单片机的话,也是可以的,但是比较的麻烦。此时需要用到内部定时器来实现,可用两个定时器实现,也可以用一个定时器实现。      用两个定时器的方法是用定时器T0来控制频率,定时器T1来控制占空比。大致的的编程思路是这样的:T0定时器中断让一个I0口输出高电平,在这个定时器T0的中断当中起动定时器T1,而这个T1是让IO口输出低电平,这样改变定时器T0的初值就可以改变频率,改变定时器T1的初值就可以改变占空比。      下面重点介绍用一个定时器的实现PWM的方法。因为市面上的智能小车所采用的电机大多数为TT减速电机,通过反复的实验,此电机最佳的工作频率为1000HZ(太高容易发生哨叫,太低电机容易发生抖动),所以下面以周期为1ms(1000HZ)进行举例,要产生其它频率的PWM波,程序中只需作简单修改即可。   用一个定时器时(如定时器T0),首先你要确定PWM的周期T和占空比D,确定了这些以后,你可以用定时器产生一个时间基准t,比如定时器溢出n次的时间是PWM的高电平的时间,则D*T=n*t,类似的可以求出PWM低电平时间需要多少个时间基准n'。   因为这里我们是产生周期为1ms(1000HZ)的PWM,所以可设置中断的时间间隔为0.01ms,,然后中断100次即为1ms。在中断子程序内,可设置一个变量如time,在中断子程序内,有三条重要的语句:   1、当time=100时,time清零(此语句保证频率为1000HZ), 2、当timen时(n应该在0-100之间变化开),让单片相应的I/O口输出高电平,3、当time   2、程序1,使单片机的I/O口输出固定频率的PWM波   下面按上面的思路给出一个具体程序: /*******************************************************************/ /* 程序名:单片机输出固定频率的PWM波*/ /* 晶振:11.00592 MHz CPU型号:STC89C52 */ /* 功能:P2^0口输出周期为1ms(1000HZ),占空比为%80的PWM波*/ /*****************************************************************/ #include #define uint unsigned int #define uchar unsigned char   sbit PWM1=P2^0;//接IN1 控制正转 sbit PWM2=P2^1;//接IN2 控制反转 uchar time;   void main() {        TMOD=0x01;//定时器0工作方式1        TH0=0xff;//(65536-10)/256;//赋初值定时        TL0=0xf7;//(65536-10)%256;//0.01ms        EA=1;//开总中断        ET0=1;//开定时器0中断        TR0=1;//启动定时器0        while(1)        {                              }                      }   void delay(uint z) {        uint x,y;        for(x=z;x0;x--)               for(y=500;y0;y--); }   void tim0() interrupt 1 {        TR0=0;//赋初值时,关闭定时器        TH0=0xff;//(65536-10)/256;//赋初值定时        TL0=0xf7;//(65536-10)%256;//0.01ms        TR0=1;//打开定时器          time++;        if(time=100) time=0;//1khz        if(time=20) PWM1=0;//点空比%80        else PWM1=1;        PWM2=0; }   程序说明:   1、关于频率的确定:对于11.0592M晶振, PWM输出频率为1KHZ,此时设定时器0.01ms中断一次,时中断次数100次即为1KHZ( 0.01ms*100=1ms,即为1000HZ)此时, 定时器计数器赋初值为TH0=FF,TL0=F7。   2、关于占空比的确定:此时我们将来time的值从0-100之间进行改变,就可以将占空比从%0-%100之间进行变化,上面程序中time=20时 PWM1=0; else PWM1=1;意思就是%20的时间输出低电平,%80的时间输出高电平,即占空比为%80。如需得到其它占空比,如%60,只需将time的值改为40即可。(程序为if(time=40) PWM1=0;else PWM1=1;)   当然编写程序时也可以定义一个标志位如flag,根据flag的状态决定输出高平还是低电平,假设定义flag=1的时候输出高电平,用一个变量去记录定时器中断的次数,每次中断就让记录中断次数的变量+1,在中断程序里面判断这个变量的值是否到了 n ,如果到了说明高电平的时间够了,那么就改变flag为0,输出低电平,同时记录中断变量的值清零,每次中断的时候依旧+1,根据flag=0的情况跳去判断记录变量的值是否到了 n' 如果到了,说明PWM的低电平时间够了,那么就改flag=1,输出改高电平,同时记录次数变量清零,重新开始,如此循环便可得到你想要的PWM波形,这种方法我们这里不在举例,请自己去试着书写。   3、程序2,使用单片机I/O口输出PWM波,并能通过按键控制正反转     在程序中我们通常需要控制电机的正反转,如通过一个按键控制正反转,此时我们也可以设置一个标志位如flag。在主程序中当按键每次被按下时,flag相应取反。然后在子程序中当flag为1时,进行正转程序,当flag为0时执行反转程序。下面的程序功能为单片机I/O口P2^0、P2^1输出1000HZ,占空比为%50,并能过P3^7按键控制正电机的正反转。   /*******************************************************************/ /* 程序名:PWM直流电机调速 */ /* 晶振:11.00592 MHz CPU型号:STC89C52 */ /* 功能:直流电机的PWM波控制,可以通过按键控制正反转 */ /*****************************************************************/ #include   #define uint unsigned int #define uchar unsigned char   uchar time,count=50,flag=1;//低电平的占空比   sbit PWM1=P2^0;//PWM 通道 1,反转脉冲 sbit PWM2=P2^1;//PWM 通道 2,正转脉冲 sbit key_turn=P3^7; //电机换向   /************函数声明**************/ void delayxms(uint z); void Motor_turn(void); void timer0_init(void);   /*********主函数********************/ void main(void) {         timer0_init();         while(1)         {                Motor_turn();         } }   /****************延时处理**********************/ void delayxms(uint z)//延时xms程序 {     uint x,y;         for(y=z;x0;x--)                for(y=110;y0;y--); }   /************电机正反向控制**************/ void Motor_turn(void) {         if(key_turn==0)         {                 delayxms(2);//此处时间不能太长,否者会的中断产生冲突                 if(key_turn==0)                 {                 flag=~flag;                 }                 while(!key_turn);         } }   /***********定时器0初始化***********/ void timer0_init(void) {         TMOD=0x01; //定时器0工作于方式1         TH0=(65536-10)/256;         TL0=(65536-10)%256;         TR0=1;         ET0=1;         EA=1; }   /**************定时0中断处理******************/ void timer0_int(void) interrupt 1 {                 TR0=0;//设置定时器初值期间,关闭定时器         TH0=(65536-10)/256;         TL0=(65536-10)%256;         TR0=1;                 if(flag==1)//电机正转         {                 PWM1=0;                 time++;                 if(time div=""                 {                 PWM2=1;                 }             else             PWM2=0;                     if(time=100)             {                 time=0;             }         }         else //电机反转         {                PWM2=0;                 time++;             if(time div=""             {                 PWM1=1;             }             else                 PWM1=0;                         if(time=100)             {                 time=0;             }         } }   4、程序4、使单片机输出PWM,并能控制正反转和实现调速   为了使大家彻底掌握此方面,下面再给出一个复杂一点的程序,实现的功能为通过一个按键控制正反转并通过另外两个按键使之可以在0到20级之间调速的程序。   /*******************************************************************/ /* 程序名:PWM直流电机调速 */ /* 晶振:11.00592 MHz CPU型号:STC89C52 */ /* 直流电机的PWM波控制,可以通过按键控制正反转并在0到20级之间调速 */ /*****************************************************************/ #include   #define uint unsigned int #define uchar unsigned char   uchar time,count=50,flag=1;//低电平的占空比   sbit PWM1=P2^0;//PWM 通道 1,反转脉冲 sbit PWM2=P2^1;//PWM 通道 2,正转脉冲 sbit key_add=P3^5;//电机加速 sbit key_dec=P3^6;//电机减速 sbit key_turn=P3^7;//电机换向   /************函数声明**************/ void delayxms(uint z); void Motor_turn(); void Motor_add(); void Motor_dec(); void timer0_init();   /*********主函数********************/ void main() {     timer0_init();     while(1)     {        Motor_turn();        Motor_add();        Motor_dec();     } }   /****************延时处理**********************/ void delayxms(uint z)//延时xms程序 {     uint x,y;     for(y=z;x0;x--)        for(y=110;y0;y--); }   /************电机正反向控制**************/ void Motor_turn() {     if(key_turn==0)     {         delayxms(2);//此处时间不能太长,否者会的中断产生冲突         if(key_turn==0)         {            flag=~flag;         }         while(!key_turn);     } }   void Motor_add()//电机加速 {     if(key_add==0)     {         delayxms(2);//此处时间不能太长,否者会的中断产生冲突         if(key_add==0)         {            count+=5;            if(count=100)            {               count=0;            }         }         while(!key_add);     } }   void Motor_dec()//电机加减速 {     if(key_dec==0)     {         delayxms(2);//此处时间不能太长,否者会的中断产生冲突         if(key_dec==0)         {            count-=5;            if(count=100)            {               count=0;            }         }         while(!key_dec);     } }   /***********定时器0初始化***********/ void timer0_init() {     TMOD=0x01; //定时器0工作于方式1     TH0=(65536-10)/256;     TL0=(65536-10)%256;     TR0=1;     ET0=1;     EA=1; }   /**************定时0中断处理******************/ void timer0_int() interrupt 1 {         TR0=0;//设置定时器初值期间,关闭定时器     TH0=(65536-10)/256;     TL0=(65536-10)%256;     TR0=1;         if(flag==1)//电机正转     {        PWM1=0;        time++;         if(time div=""         {            PWM2=1;         }         else         PWM2=0;             if(time=100)         {            time=0;         }     }     else //电机反转     {        PWM2=0;         time++;         if(time div=""         {            PWM1=1;         }         else            PWM1=0;                 if(time=100)         {            time=0;         }     } }   5、利用单片机输出PWM简单控制小车直行   相信通过上面的讲解,大家已经能够很好的撑握如何利用51单片机产生PWM波下面给出一个程序,通过单片机两个I/O口输出PWM波,让小车直行。 #include #define uint unsigned int #define uchar unsigned char   sbit PWM1=P2^0;//接IN1 控制正转 sbit PWM2=P2^1;//接IN2 控制反转   sbit PWM3=P2^2;//接IN3 控制正转 sbit PWM4=P2^3;//接IN4 控制反转   sbit PWM5=P2^4;//接IN3 控制正转 sbit PWM6=P2^5;//接IN4 控制反转   sbit PWM7=P2^6;//接IN3 控制正转 sbit PWM8=P2^7;//接IN4 控制反转   uchar time;   void main() {     TMOD=0x01;//定时器0工作方式1     TH0=0xff;//(65536-10)/256;//赋初值定时     TL0=0xf7;//(65536-10)%256;//0.01ms     EA=1;//开总中断     ET0=1;//开定时器0中断     TR0=1;//启动定时器0     while(1)     {                }          }   void delay(uint z) {     uint x,y;     for(x=z;x0;x--)        for(y=500;y0;y--); }   void tim0() interrupt 1 {     TR0=0;//赋初值时,关闭定时器     TH0=0xff;//(65536-10)/256;//赋初值定时     TL0=0xf7;//(65536-10)%256;//0.01ms     TR0=1;//打开定时器       time++;     if(time=100) time=0;//1khz     PWM2=0;     PWM4=0;        if(time=75) PWM1=1;     else PWM1=0;     if(time=80) PWM3=1;     else PWM3=0;       PWM6=0;     PWM8=0;        if(time=50) PWM5=1;     else PWM5=0;     if(time=50) PWM7=1;     else PWM7=0;      }   本文转自51hei,单片机教程 ) ) ) ) 时,让单片相应的i
  • 热度 22
    2015-6-4 14:58
    1363 次阅读|
    2 个评论
    1、单片机IO口上电后默认是高电平。(P1、P2、P3口内部上拉,若P0口未接上拉电阻的话,默认是高阻态) 2、单片机工作频率=晶振频率/12,即使用12MHz的晶振,实际工作频率为1MHz,一个机器周期为1us。 3、单片机常用11.0592MHz的晶振,主要是保证串口通信的同步。比如说在9600波特率下每位数据电平持续96个机器周期,因为是整数值,不会产生误差。若使用12MHz的晶振,高波特率下通信容易产生误码。 4、三极管的使用:在模拟电路中,输入为高频模拟信号时,三极管一般工作在放大模式下。在数字电路中,三极管一般作为开关用,工作在饱和模式下。 5、在单片机数据线和地址线复用的情况下必须使用锁存器,可在工作时锁住地址信号,传输数据信号,以防止传数据时地址线被数据所影响。 6、普通发光二极管正向压降为1.6v-2.1v,工作电流为3-20mA。计算LED限流电阻时必须使用到此参数,一般取压降为1.7v,电流为3mA,使用5V电压的情况下限流电阻为:(5v-1.7v)/3mA=3.3v/3mA=1.1kohm,可取1kohm。
  • 热度 38
    2012-2-4 11:39
    10490 次阅读|
    12 个评论
      CortexM0与51单片机的比较  前些天开发对一个老产品升级,进行MCU选型,老产品是一个IIC接口IO输出扩展板,   而新产品要具备RS485协议接口,同时具有IIC接口(找了好久,没有找到有51自带IIC  接口,由于该MCU是要作从机的,因此IO口模拟IIC的方式走不通)。该产品对MCU的  要求是:具有1个串口,至少1个IIC接口(有两个最好),至少20个IO可用,MCU处  理能力无要求;按照从满足项目需求原则、价格原则、供货原则、开发难度原则(资料是  否丰富,调试是否容易)等原则容易出发,Cortex M0内核的MCU映入我的眼帘。  下面以我选的Cortex M0内核的NXP的芯片LPC1114和51单片机华邦的W78E516BP比   较为例:  LPC1114特性概览如下:  1、Cortex M0内核,32位MCU,最高工作频率50 MHz,NVIC嵌入内核中断模式,PLL  2、SWD调试方式,JLINK v8可用于调试中  3、32KB Flash,8KB SRAM  4、支持IAP ISP下载固件  5、42个普通I/0,可复用,可配置为电平或边缘触发中断模式  6、1个UART1,1个IIC接口,2个SSP,8路10位ADC,WDT,4TC  7、具有LQFP48、PLCC44、HVQFN33等封装模式    W78E516BP特性概览 1、全静态设计的CMOS 8位微处理器最高达 40MHz (除以12,指令执行速度只有3.33M)  2、64K(ISP功能)+4K字节的辅助 ROM,512Byte RAM 3、36个I/0口,3个 TC,一个全双工串行口(UART) 4、8个中断源,2级中断能力  5、 封装: DIP40,PLCC44,PQFP 44   价格:LPC1114 8块含税,W78E516BP 7.6含税,价格差异不大 51单片机一般自带RAM都很少,因此在编写程序要特别注意RAM资源的分配,程序的架构无法做的很好。 Cortex M0是32位的,处理能力强,Flash和Ram够用,外设多,中断功能强,调试方便,众所周知,51在线调试不太方便,需要开发人员去辅助调试。 一比较,51的以后的市场肯定会不断受到M0的冲击。不过51的普遍使用,价格优势仍一直会存在市场。 作为我个人而言,在后续成本不是很敏感的产品设计时,会更多的考虑Cortex M0替代51使用了,也为后续的升级打下MCU基础。 
  • 热度 16
    2011-11-24 15:02
    1981 次阅读|
    0 个评论
    原文出自: 电子发烧友论坛——单片机论坛 本课以AT89S51单片机最小系统来教你如何实现单片机编程,该程序驱动单片机P1.7端口上的发光二极管不停闪烁,系统程序用keil 汇编语言编写,电路参考下图1所示。   《51单片机最小系统原理及编程电路设计》     首先来认识一下发光二极管(LED),发光二极管实物如下图2所示,发光二极管具有单项导电,体积小、耗电省、寿命长、响应速度快、显示清晰等特点,广泛用于电子电路中当作LED数码管、LED指示灯、LED电子显示屏,既然是51单片机最小系统我们当然只进行了最简单的电路设计与编程         图2: 《发光二极管介绍》   发光二极管导通时,产生一个正向的工作电流IF,工作电流根据发光二极管的材料、功率等不同,额定电流一般在10~40mA左右,发光二极管导通时的正向压降VF比较大,一般为1.5~3V(普通硅二极管约为0.7V)。因此在正常使用中,为了保证发光二极管在电源电压V的作用下管子的工作电流不超过额定值,必须给发光二极管串联一只限流电阻R,R的阻值可由下式算出:R=(V-VF)/IF。其中V为工作电源电压,VF为发光二极管的正向压降,IF为额定工作电流。   从上面原理图1可知,当单片机的P1.7输出低电平(0V)时,有正向工作电流流过发光二极管,发光二极管就亮;相反,当P1.7输出高电平(5V)时,发光二极管没有足够电压差产生工作电流,此时发光二极管不亮。因此,程序中只需交替让单片机的P1.7输出低电平“0”和高电平“1”就可以让发光二极管闪烁发光。   下面以51单片机汇编语言来编程,让某个端口输出高电平语句是SETB,让端口输出低电平的语句是CLR语句,让P1.7端口输出高电平的语句是: SETB  P1.7; 让P1.7端口输出低电平的语句是: CLR  P1.7,实现发光二极管LED闪烁的编程思路如下图3所示。     图3: 《51单片机最小系统原理编程框图》   完整的源程序如下:   ;******** 51单片机最小系统原理及编程电路设计主程序 ********   MAIN:  CLR   P1.7   ;主程序开始,P1.7输出低电平"0",让点亮发光二极管       ACALL  DELAY   ;调用延时子程序延时一段时间,让发光二极管亮一段时间       SETB   P1.7   ;P1.7输出高电平"1",熄灭发光二极管       ACALL  DELAY   ;调用延时子程序延时一段时间,让发光二极管熄灭一段时间       AJMP   MAIN   ;跳转到程序开头重复执行   ;******** 下面是延时子程序 ********   DELAY: MOV   R7,#255   Y1:   MOV   R6,#255       DJNZ   R6,$       DJNZ   R7,Y1       RET        ;延时子程序返回       END        ;程序结束     启动“Keil uVision2”单片机集成开发环境,如没有请再这里下载 keil下载 建立一个新工程,输入上面的源程序,最后编译得到一个lich1.hex目标文件,用编程器把lich1.hex写入单片机AT89S51中,插到实验板上就可以看到第一个程序的运行效果了(P1.7端口的发光二极管不停闪烁)。这就是我们学习的第一个最简单的程序,是一个完整的单片机开发过程,再复杂庞大的程序都是由简单的语句、程序构成的,希望该教程能给初学者对单片机开发有一个感性的认识。不懂如何在Keil中编辑源程序的初学者请看 keil教程         图4: ISP编程器将产生的目标程序lich1.hex写入AT89S51单片机   图5:单片机插入实验板上程序的运行效果 单片机的学习是一个循序渐进的过程,制作单片机最小系统,并彻底了解其原理,能把你快速带入单片机世界的大门,这只是一个最简单的制作,有什么问题,欢迎大家回复帖子。  
相关资源