51单片机j基础C程序架构

来源:互联网 发布:vk7201数据 编辑:程序博客网 时间:2024/06/05 14:10

keil基本步骤:

(1)新建一个工程:Project——New uVision Project

(2)选择型号:AT89C52

(3)新建.c文件:File——new——a.c

保存为:.c后缀

(4)添加.c文件:

(5)编写程序


以下是基本程序架构:很重要的笔记

A.    基本程序框架:(点亮小灯)

#include<reg52.h>

sbit LED=P1^0;

void main (void)

{

   LED=0;  // P1 = 0xfe;

while (1)    

  {

        //空循环

  }

}

 

B.     for循环语句:(小灯循环点亮)

unsigned char i;

for(i=0;i<10;i++)

{;}

执行顺序:i=0; —— i<10; —— {}中的内容—— i++ ——。。。

 

C.     左移/右移(小灯逐个往左/右移动亮)

P1=0xfe;  // P1=0x7f;

for(i=0;i<8;i++)   //加入 for循环,表明for循环大括号中的程序循环执行8次

      {

       Delay(50000);

       P1<<=1;   //P1>>=1;

       }

 循环左移/右移:

    for(i=0;i<8;i++)   //加入 for循环,表明for循环大括号中的程序循环执行8次

      {

        Delay(50000);

        P1<<=1;   //P1>>=1;

       P1=P1|0x01;  //P1=P1|0x80;

     //左移后,最右端自动赋值0,所以需要该语句赋值1

      }

  P1=0xfe;   //P1=0x7f;        //重新赋初始值

 

D.    数组的使用:

unsigned char code table[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe, 0xff,0xff,0x00,0x00, 0x55,0x55,0xaa,0xaa};

for(i=0;i<16;i++)

{

 P1=table[i];

     Delay(3000);

}

 

E.     PWM调光

sbit LED0=P1^0;

void main (void)

{

unsigned int CYCLE=600,PWM_LOW=0;

     while(1)

{

  LED0=1;

  Delay(6000);

 

for(PWM_LOW=1;PWM_LOW<CYCLE;PWM_LOW++)

{

  LED0=0;

  Delay(PWM_LOW);

  LED0=1;

Delay(CYCLE-PWM_LOW);

}

 

LED0=0;

for(PWM_LOW=CYCLE-1;PWM_LOW>0;PWM_LOW--)

{

  LED0=0;

  Delay(PWM_LOW);

  LED0=1;

  Delay(CYCLE-PWM_LOW);

}

}

 

F.     共阳数码管显示(循环显示数字)

   unsignedchar code dofly_table[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,};

   P1=dofly_table[i];

{

   P1=dofly_table[i];

   Delay(60000);

}

 

G.    独立按键(按键控制数码管显示数字) switch选择语句

switch(P3)  //P3口作为独立按键输入端

{

 case0xfe:P1=dofly_table[1];break;

case 0xfd:P1=dofly_table[2];break;

default:break;

}

H.     数码管静态显示:位锁存与段锁存(8位数码管显示其中之一/二)

   #define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换

sbit LATCH1=P2^2;//定义锁存使能端口 段锁存

sbit LATCH2=P2^3;//                位锁存

main()

{

   while(1)

{

   DataPort=0xfe; //取位码 第一位数码管选通,即二进制1111 1110   之一

//  DataPort=0x7e; //取位码 第一位数码管选通,即二进制0111 1110  之二

   LATCH2=1;     //位锁存

   LATCH2=0;

 

   DataPort=0x4F; //取显示数据,段码 “3”共阴字符码

   LATCH1=1;     //段锁存

   LATCH1=0;

}

}

 

I.       数码管动态显示:位锁存与段锁存

   #define DataPort P0 //定义数据端口 程序中遇到DataPort 则用P0 替换

sbit LATCH1=P2^2;//定义锁存使能端口 段锁存

sbit LATCH2=P2^3;//                位锁存

  unsignedchar code dofly_DuanMa[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

// 显示段码值01234567

unsigned char codedofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};

//分别对应相应的数码管点亮,即位码

  main()

{

 unsigned char i=0;

   while(1)

     {

          DataPort=dofly_WeiMa[i]; //取位码

      LATCH2=1;     //位锁存

      LATCH2=0;

 

      DataPort=dofly_DuanMa[i]; //取显示数据,段码   //DataPort=dofly_DuanMa[num+i];

      LATCH1=1;     //段锁存

      LATCH1=0;

 

          Delay(200); //扫描间隙延时,时间太长会闪烁,太短会造成重影

          i++;

          if(8==i)   //检测8位扫描完全结束?如扫描完成则从第一个开始再次扫描8位

            i=0;

     }

}

 

J.      定时器0

  (1)模式013位计数器)

void Init_Timer0(void)   //初始化

{

TMOD &= 0xF0;   //定时器0运行在模式013位计数器

                // GATE0=0;C/T0#=0; M1=0; M0=0;

TH0 = 0x00;     //设置初值0x00,所以计数值为8192,若是时钟频率为12MHz

TL0 = 0x00;     //则8192μs中断一次 ;注:213次方是8192

ET0=1;    //允许定时器0中断

EA=1;     //允许总中断

TR0=1;    //启动定时器0

}

voidTimer0_isr(void) interrupt 1

{ }

 

(2)模式116位定时器)  重要

 void Init_Timer0(void)   //初始化

{

      TMOD |= 0x01;         //模式116位定时器,使用"|"符号在使用多个定时器时不受影响  

 TH0=0x00;        //给定初值,这里用定时器最大值从0开始计数一直到65535溢出

       TL0=0x00;      //一次最多可定时65.536ms

//  TH0=(65535-50000)/256=0x3c=6010;   //50ms

//  TL0=65535-50000%256=0xb0=17610);

      EA=1;            //总中断打开

      ET0=1;           //定时器中断打开

      TR0=1;           //定时器开关打开

}

void Timer0_isr(void) interrupt 1 using 1

{

  TH0=0x00;   //重新赋值

  TL0=0x00;

LED=~LED;   //定时到了:执行的内容

}

注:时间计算

51单片机1个机器周期=12个时钟周期,频率为12MHZ,则一个机器周期为1US,具体到定时器程序就是,假如你想定1MS,那么单片机每次加一个一,就要过1US,那么1MS就要加1000次,所以用65535-1000=64535;再把64535换成16进制为FC17,把FC付给TH0,17给TLO,即可定时1MS,因为65535他就溢出进入中断。

  

(3)模式28位重装模式)

  void Init_Timer0(void)   //初始化

{

TMOD &= 0xF0;  //模式2,8位重装模式

TMOD|=0x0A;    //GATE0=1;C/T0#=0; M1=1; M0=0;

TH0=0x06;         //设定初值;0x06=  0000 0110

        TL0=0x06;       //计数值为250,若为12MHz,相当于250us

       EA=1;            //总中断打开

       ET0=1;           //定时器中断打开

       TR0=1;           //定时器开关打开

}

void Timer0_isr(void) interrupt 1 using 1

{

  n=n++;   //没中断一次,n+1,每两次中间间隔250us

  if(n=40)   //n=40,就是中断40次,相当于250*4=10ms

       {

n=0;

    m++; //每10ms,m+1

    if(m==100) //m=100,相当于10ms*100=1s

    {m=0;

}

 }

 

(4)模式3

定时器0工作于方式3 时,占用了定时器1的TR1和TF0。

 

K.    定时器1(功能与定时器0一样,定时器1还可以用做串口的波特率发生器

   voidInit_Timer1(void)  //初始化

{

    TMOD |= 0x10;    //模式116位定时器,使用"|"符号在使用多个定时器时不受影响

 TH1=0x00;        //给定初值,这里用定时器最大值从0开始计数一直到65535溢出

     TL1=0x00;

//  TH0=(65535-50000)/256=0x3c=6010;   //50ms

//  TL0=65535-50000%256=0xb0=17610);

 EA=1;            //总中断打开

 ET1=1;           //定时器中断打开

 TR1=1;           //定时器开关打开

}

void Timer1_isr(void) interrupt 3 using 1

{

 TH1=0x00;          //重新赋值

 TL1=0x00;

 LED=~LED;       //LED闪烁

}

 

L.     定时器2

voidTIM2Inital(void)   //初始化

{

  RCAP2H = (65536-60000)/256;  //晶振12M 60ms 16bit 自动重载

  RCAP2L = (65536-60000)%256;

  ET2=1;                      //打开定时器中断

  EA=1;                      //打开总中断

  TR2=1;                     //打开定时器开关

}

  void TIM2(void) interrupt 5 using 1//定时器2中断

{

   TF2=0;

LED=~LED;       //执行函数

   }  

 

M.   产生方波(定时器0模式1

(1)产生1ms方波

     sbitOUT=P1^2;

     voidInit_Timer0(void)

{

       TMOD |= 0x01;//使用模式1,16位定时器

 //TH0=0x00;   //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出

 //TL0=0x00;

 EA=1;            //总中断打开

        ET0=1;           //定时器中断打开

        TR0=1;           //定时器开关打开

}

main()

{

 Init_Timer0();

 while(1);

}

void Timer0_isr(void) interrupt 1 using 1

{

 TH0=(65536-500)/256;            //重新赋值 12M晶振计算,指令周期1uS,

 TL0=(65536-500)%256;         //1mS方波半个周期500uS,即定时500次

                             //溢出然后输出端取反

 OUT=~OUT;        //用示波器可看到方波输出

}

(2)产生200ms方波

  void Timer0_isr(void)interrupt 1 using 1

{

 staticunsigned char i;

      TH0=(65536-10000)/256;          //重新赋值 12M晶振计算,指令周期1uS,

       TL0=(65536-10000)%256;     //直接定时器不够用,定时10ms,然后循环10次

 i++;

 if(i==11)

 {

          i=0;

          OUT=~OUT;        //用示波器可看到方波输出

       }

}

 

N.    独立按键(控制一个led

  KEY=1; //按键输入端口电平置高

while (1)         //主循环

    {

   if(!KEY)  //如果检测到低电平,说明按键按下

     LED=0;

     else

LED=1;

}

一个led状态转换:

 while (1)         //主循环

  {

  if(!KEY)  //如果检测到低电平,说明按键按下

    {

        DelayMs(10); //延时去抖,一般10-20ms

    if(!KEY)     //再次确认按键是否按下,没有按下则退出

          {

       while(!KEY);//如果确认按下按键等待按键释放,没有释放则一直等待

              {

                 LED=!LED;//释放则执行需要的程序

                    }}}}

 

O.    外部中断0P3^2

    main()

{

     P1=0x55;       //P1口初始值

     EA=1;          //全局中断开

     EX0=1;         //外部中断0开

     IT0=0;         //电平触发

//IT0=1;        //边沿触发

      while(1)

      {

                 //在此添加其他程序

      }

}

     voidISR_Key(void) interrupt 0 using 1

{

 P1=~P1;     //进入中断程序执行程序,

//此时可以通过 EA=0指令暂时关掉中断   

}

 

P.     外部中断1P3^3

     main()

{

       LED=0;        //LED灯点亮

       EA=1;         //全局中断开

       EX1=1;         //外部中断0开

  IT1=0;         //T1=0表示电平触发

  // IT1=1;         //IT1=1表示边沿触发

  while(1)

       {

          //在此添加其他程序

       }

}

      void ISR_INT1(void) interrupt 2

{

  if(!INT1)

       {

           DelayMs(10);//在此处可以添加去抖动程序,防止按键抖动造成错误

           if(!INT1)

           while(!INT1);//等待按键释放

             {

                LED=!LED;  

             }

         }

}

 

Q.    T0/T1外部计数输入

    voidInit_Timer0(void)

{

     TMOD |= 0x01 | 0x04; //模式1,16位计数器,用"|"符号在使用多个定时器时不受影响   

 TH0=0xFF;       //给定初值

     TL0=245;         //从245计数到255

 EA=1;            //总中断打开

     ET0=1;           //定时器中断打开

     TR0=1;           //定时器开关打开

}

main()

{

 Init_Timer0();

 while(1);

}

void Timer0_isr(void) interrupt 1 using 1

{

 TH0=0xFF;           //重新给定初值

 TL0=245;

 LED=~LED;        //指示灯反相,可以看到闪烁

}

 

void Init_Timer1(void)

{

 TMOD |= 0x10 | 0x40;    //模式1,16位计数器,用"|"符号用多个定时器时不受影响 

 TH1=0xFF;           //给定初值

 TL1=245;         //从245计数到255

 EA=1;            //总中断打开

 ET1=1;           //定时器中断打开

 TR1=1;           //定时器开关打开

}

 

R.     看门狗溢出测试

sfr  WDTRST  =  0xA6;

voidRst_Watchdog( void )   //喂狗

{

       WDTRST = 0x1E; //先赋值1E 然后赋值E1

    WDTRST = 0xE1;

}

void main( void)

{

       int i;           // 设置看门狗时间为1个时钟循环后

       Rst_Watchdog();   //关看门狗一个时钟循环

       for( i = 0; i < 500; i++)

       {

              Rst_Watchdog();               

       }

    P1=0x00;

       while(!key)                 //按下按键不松开,表示程序一直在按键处循环,

                                //并用LED显示0x55

       {

        P1=0x55;                     //模拟出错 正常情况应该一直显示LED,

                                //但是加看门狗之后不间断复位,倒是LED闪烁

       }

}

 

S.     步进电机转动原理

   sbit A1=P1^0; //定义步进电机连接端口

sbit B1=P1^1;

sbit C1=P1^2;

sbit D1=P1^3;

#define Coil_A1 {A1=1;B1=0;C1=0;D1=0;}//A相通电,其他相断电

#define Coil_B1 {A1=0;B1=1;C1=0;D1=0;}//B相通电,其他相断电

#define Coil_C1 {A1=0;B1=0;C1=1;D1=0;}//C相通电,其他相断电

#define Coil_D1 {A1=0;B1=0;C1=0;D1=1;}//D相通电,其他相断电

#define Coil_OFF {A1=0;B1=0;C1=0;D1=0;}//全部断电

unsigned char Speed;

main()

{

 //unsigned int i=64*16; //转2周停止

 Speed=5; //调整速度

 while(1) 

  {        

     Coil_A1                 //遇到Coil_A1  用{A1=1;B1=0;C1=0;D1=0;}代替

     DelayMs(Speed);         //改变这个参数可以调整电机转速 ,

                                //数字越小,转速越大,力矩越小

     Coil_B1

     DelayMs(Speed);

     Coil_C1

     DelayMs(Speed);

     Coil_D1

     DelayMs(Speed);

  }

}

 

T.      串口通讯

    voidInitUART  (void)

{

      SCON  = 0x50;                     // SCON: 模式 1, 8-bit UART, 使能接收 

      TMOD |= 0x20;               //TMOD: timer 1, mode 2, 8-bit 重装

      TH1   = 0xFD;               // TH1:  重装值 9600 波特率 晶振 11.0592MHz 

      TR1   = 1;                  // TR1:  timer 1 打开                        

      EA    = 1;                  //打开总中断

      //ES    = 1;                  //打开串口中断

}

void SendByte(unsigned char dat)  //发送一个字节

{

 SBUF = dat;

 while(!TI);

      TI = 0;

}

void SendStr(unsigned char *s)  //发送一个字符串

{

 while(*s!='\0')// \0 表示字符串结束标志,

                //通过检测是否字符串末尾

  {

  SendByte(*s);

  s++;

  }

}

void main (void)

{

InitUART();

while (1)                      

    {

      SendStr("UART test,技术论坛:www.doflye.net thankyou!");

         DelayMs(240);//延时循环发送

      DelayMs(240);

    }

}

 

U.     串口通讯中断

    voidInitUART  (void)

{

      SCON  = 0x50;                     // SCON: 模式 1, 8-bit UART, 使能接收 

      TMOD |= 0x20;               //TMOD: timer 1, mode 2, 8-bit 重装

      TH1   = 0xFD;               // TH1:  重装值 9600 波特率 晶振 11.0592MHz 

      TR1   = 1;                  // TR1: timer 1 打开                        

      EA    = 1;                  //打开总中断

      // ES    = 1;                  //打开串口中断

void main (void)

{

InitUART();

SendStr("UART test,技术论坛:www.doflye.net 请在发送区输入任意信息");

ES    = 1;                  //打开串口中断

while (1)                      

    { }

}

void UART_SER (void) interrupt 4 //串行中断服务程序

{

    unsigned char Temp;          //定义临时变量

    if(RI)                        //判断是接收中断产生

     {

         RI=0;                      //标志位清零

         Temp=SBUF;                 //读入缓冲区的值

         P1=Temp;                   //把值输出到P1口,用于观察

      SBUF=Temp;                 //把接收到的值再发回电脑端

        }

   if(TI)                        //如果是发送标志位,清零

     TI=0;

}

 

V.     RS485通讯原理(与串口通讯类似)

    voidmain (void)

{

InitUART();

Ctrl_EN=1; //发送模式(多了这条设定)

while (1)                      

      {

       SendStr("UART test,技术论坛:www.doflye.net thank you!");

           DelayMs(240);//延时循环发送

        DelayMs(240);

     }

}

 

0 0
原创粉丝点击