打印
[单片机类]

蓝桥杯单片机笔记 ———————CT107D平台

[复制链接]
21632|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
一路向北lm|  楼主 | 2017-12-30 11:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 一路向北lm 于 2017-12-30 12:01 编辑

1.IO口编程

IO编程,该开发板使用了573锁存器,通过P2口的5,6,7位连接3-8译码器,扩展出了8个口,其中4个口分别连接4个573锁存器,这里以LED的锁存器来举例:

分析代码:

P2=((P2&0x1f)|0x80);其中0x1f=0001 1111,P2与0x1f进行与运算,高三位清零,其余位保持原来状态,不改变,即把控制3-8译码器的高三位留出来:

接着再或上0x80;容易发现0x80=1000 0000;或运算,与1或结果为1,与0或结果不变,所以或上0x80只需看P2的高三位,则高三位为100,对应3-8译码器的话,P2^7=1;P2^6=0;P2^5=0;所以输出Y4=0;Y4再经过与非运算,则输出Y4C=1;即LED对应的锁存器的片选信号被选中,锁存器打通,接下来就可以对P0口进行操作,操作完之后,P2=P2&0x1f;P2高三位直接清零,此时Y4C=0,则把锁存器锁上了。类似的方法,数码管、蜂鸣器等都是如此操作,选中锁存器代码:P2=((P2&0x1f)|(这里填对应锁存器的位移号))。


相关帖子

沙发
一路向北lm|  楼主 | 2017-12-30 12:00 | 只看该作者
2.数码管动态扫描和定时器

数码管显示分为段选和位选,

数码管定义和显示函数:

   code unsigned char tab[] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

unsigned char dspbuf[]={10,10,10,10,10,10,10,10};

unsigned char dspcom=0;

void display()

{

//段选,消隐

P2=((P2&0x1f)|0xe0);

P0=0xff;

P2=P2&0x1f;

//位选

P2=((P2&0x1f)|0xc0);

P0=(1<<dspcom);

P2=P2&0x1f;

//段码输入

P2=((P2&0x1f)|0xe0);

P0=tab[dspbuf[dspcom]];

P2=P2&0x1f;

if(++dspcom==8)

   dspcom=0;

}

这里1左移dspcom位,刚开始dspcom=0,则1左移dspcom位依旧为1,接着dspcom每次自增1,1对应二进制0000 0001,即把1每次向左移,每次都比上一次多移一位,直至8位移完,对应8个数码管。


使用特权

评论回复
板凳
一路向北lm|  楼主 | 2017-12-30 12:04 | 只看该作者

3.定时器配置:

这里只需记住定时器的配置,首先有两个定时器,T0和T1,定时器有4种工作方式0,1,2,3;其中最常用的是方式1(16位),其次是方式2(8位自动重装,串口通讯中断会用到)。

定时器需要配置:TMOD |=0x01;配置成使用定时器0,工作方式为1;同理使用定时器1工作方式1:TMOD |=0x10;则同时使用两个定时器且工作方式为1,那么可以:TMOD |=0x11;

定时器1配置成工作方式2:TMOD |=0x20;

接着配置(以定时器0举例):

TH0=(65535-2000)/256;//配置初值

TL0=(65535-2000)%6;

ET0=1;

TR0=1;//定时0中断

EA =1;//总中断

定时器1也是同理的,只不过0要改成1.

    接着定时中断函数和优先级:

    定时器0

        void isr_timer_0(void)  interrupt 1  //默认中断优先级 1

       {

          TH0 = (65536-2000)/256;

          TL0 = (65536-2000)%6;  //定时器重载

          display();

      }

   定时器1:

      void isr_timer_1(void)  interrupt 3  //默认中断优先级 3

     {

       TH0 = (65536-2000)/256;

       TL0 = (65536-2000)%6;  //定时器重载

      display();

    }

数码管动态扫描,显示函数放在定时中断函数里面,2ms扫一次是比较稳定的!!


使用特权

评论回复
地板
一路向北lm|  楼主 | 2017-12-30 12:06 | 只看该作者

4.矩阵键盘

矩阵键盘需要死记了!这里不再讲独立键盘

第二种单片机键盘扫描代码(没有消抖):

sfr P4^4=0xC0;

//键盘定义

sbit r1=P3^0;  //4行

sbit r2=P3^1;

sbit r3=P3^2;

sbit r4=P3^3;

//4列

sbit c1=P4^4;

sbit c2=P4^2;

sbit c3=P3^5;

sbit c4=P3^4;

//读取矩阵键盘键值

unsigned char key_scan()

{

     unsigned char key_value;

     r1=0;

     r2=r3=r4=1;

     c1=c2=c3=c4=1;

     if(!c1) key_value=0;

     else if(!c2) key_value=1;

     else if(!c3) key_value=2;

     else if(!c4) key_value=3;

    r2=0;

     r1=r3=r4=1;

     c1=c2=c3=c4=1;

     if(!c1) key_value=4;

     else if(!c2) key_value=5;

     else if(!c3) key_value=6;

     else if(!c4) key_value=7;

     r3=0;

     r2=r1=r4=1;

     c1=c2=c3=c4=1;

     if(!c1) key_value=8;

     else if(!c2) key_value=9;

     else if(!c3) key_value=10;

     else if(!c4) key_value=11;

     r4=0;

     r2=r3=r1=1;

     c1=c2=c3=c4=1;

     if(!c1) key_value=12;

     else if(!c2) key_value=13;

     else if(!c3) key_value=14;

     else if(!c4) key_value=15;

     return key_value;

}


使用特权

评论回复
5
一路向北lm|  楼主 | 2017-12-30 12:08 | 只看该作者
5.串口通讯和串口中断

串口中断配置只需记住几个寄存器就行了,

初始化:

  SCON =0x50;  //串口配置成模式1

TMOD |=0x20;//定时器1,方式2,8位自动重装

  TH1=256-(unsigbedchar)(SYSTEMCLOK/BAUDRATE/384+0.5);//定时初值

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

         TR1=1;      //启动定时器1

         EA=1;            //总中断打开

这里必须使用定时器1,不能用定时器0.

下面是模块化的函数:

void Uart_Init()

{

SCON = 0x50;

TMOD |=0x20;

TH1=256-(SYSREMCLOCK/BAUDRATE/384+0.5);

ES=1;

TR1=1;

EA=1;

}

void UartSend(unsigned char*pBuff,int length)    //发送字符串

{

unsigned char c;

int i=0;

for(i=0;i

{

  c=pBuff;

  SBUF=c;

  while(TI==0);

  TI=0;

}

}

接收数据可以这样写:

定义全局变量:

unsigned char uart_buf[100];//串口缓冲区

unsigned int  uart_Count=0;//串口数据长度

void uart_inte() interrupt 4

{

      unsigned char c;

      if(RI)

      {

             RI=0;

             c=SBUF;

             uart_buf[uart_Count]=c;

             uart_Count++;

      }                          

}

如果可以指定的接收,可以这样写

//串口中断服务函数

void isr_uart(void) interrupt 4{

    if(RI){

        RI = 0;  //清除接收标志位

        rxbuf[rxcnt] = SBUF;

        if(rxbuf[rxcnt] == '\n'){

            rxcnt = 0;

            rx_over = 1;

            ES = 0;

//回车为接收结束标志,检测到回车符后,关闭串口中断

        }     

             else{

                    rxcnt++;

             }

    }

}

当接收完一帧数据时关闭串口中断,设一个标志位,处理完之后再打开。



使用特权

评论回复
6
一路向北lm|  楼主 | 2017-12-30 12:09 | 只看该作者
6.串口发送以及接收例程

#include "reg51.h"

#include "intrins.h"

typedef unsigned char BYTE;

typedef unsigned int WORD;

BYTE code_tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};

char arry[10]="I CAN PLAY";

unsigned char x;

#define FOSC 11059200//12000000L          //系统频率

#define BAUD 115200             //串口波特率

#define NONE_PARITY     0       //无校验

#define ODD_PARITY      1       //奇校验

#define EVEN_PARITY     2       //偶校验

#define MARK_PARITY     3       //标记校验

#define SPACE_PARITY    4       //空白校验

#define PARITYBIT NONE_PARITY   //定义校验位

sfr AUXR  = 0x8e;               //辅助寄存器

sfr P_SW1   = 0xA2;             //外设功能切换寄存器1

#define S1_S0 0x40              //P_SW1.6

#define S1_S1 0x80              //P_SW1.7

sbit P22 = P2^2;

bit busy;

void SendData(BYTE dat);

void SendString(char *s);

void main()

{

    ACC = P_SW1;

    ACC &= ~(S1_S0 | S1_S1);    //S1_S0=0 S1_S1=0

    P_SW1 = ACC;                //(P3.0/RxD, P3.1/TxD)

   

//  ACC = P_SW1;

//  ACC &= ~(S1_S0 | S1_S1);    //S1_S0=1 S1_S1=0

//  ACC |= S1_S0;               //(P3.6/RxD_2, P3.7/TxD_2)

//  P_SW1 = ACC;

//

//  ACC = P_SW1;

//  ACC &= ~(S1_S0 | S1_S1);    //S1_S0=0 S1_S1=1

//  ACC |= S1_S1;               //(P1.6/RxD_3, P1.7/TxD_3)

//  P_SW1 = ACC;

//#if (PARITYBIT == NONE_PARITY)

    SCON = 0x50;                //8位可变波特率

//#elif (PARITYBIT == ODD_PARITY) || (PARITYBIT == EVEN_PARITY) || (PARITYBIT == MARK_PARITY)

  //  SCON = 0xda;                //9位可变波特率,校验位初始为1

//#elif (PARITYBIT == SPACE_PARITY)

//   SCON = 0xd2;                //9位可变波特率,校验位初始为0

//#endif

    AUXR = 0x40;                //定时器1为1T模式

    TMOD = 0x20;                //定时器1为模式2(8位自动重载)

    TL1 = (256 - (FOSC/32/BAUD));   //设置波特率重装值

    TH1 = (256 - (FOSC/32/BAUD));

    TR1 = 1;                    //定时器1开始工作

    ES = 1;                     //使能串口中断

    EA = 1;

    while(1)

      {

//   SendString(arry);

      SendString("I CAN PLAY~~\r\n");//上位机显示接收文本模式

//   SendData(x);

      }

}

void Uart() interrupt 4 using 1

{

    if (RI)//单片机接收数据,发送数字0~9,可在数码管上显示,发送hex模式

    {

        RI = 0;                 //清除RI位

//        P0 = SBUF;

             x=SBUF;//将缓存器的数据赋值给x

             P0=0xff;                //消隐

             P2|=0xe0;

             P2&=0x1f;

            

             P0=code_tab[x];                //段选

             P2|=0xe0;

             P2&=0x1f;

            

             P0=0x01;                           //位选第一位

             P2|=0xc0;

             P2&=0x3f;

   

    }

    if (TI)

    {

        TI = 0;                 //清除TI位

        busy = 0;               //清忙标志

    }

}

void SendData(BYTE dat)

{

    while (busy);               //等待前面的数据发送完成

    ACC = dat;                  //获取校验位P (PSW.0)

    if (P)                      //根据P来设置校验位

    {

#if (PARITYBIT == ODD_PARITY)

        TB8 = 0;                //设置校验位为0

#elif (PARITYBIT == EVEN_PARITY)

        TB8 = 1;                //设置校验位为1

#endif

    }

    else

    {

#if (PARITYBIT == ODD_PARITY)

        TB8 = 1;                //设置校验位为1

#elif (PARITYBIT == EVEN_PARITY)

        TB8 = 0;                //设置校验位为0

#endif

    }

    busy = 1;

    SBUF = ACC;                 //写数据到UART数据寄存器

}

void SendString(char *s)

{

    while (*s)                  //检测字符串结束标志

    {

        SendData(*s++);         //发送当前字符

    }

}

记不住可以看手册!!

#include "reg51.h"

#include "intrins.h"

typedef unsigned char BYTE;

typedef unsigned int  WORD;

#define FOSC 11059200L

#define BAUD 115200

sfr AUXR=0x8e;    //辅助寄存器

sbit P22=P2^2;

bit busy;

void SendData(BYTE dat);

void SendString(char *s);

void main()

{

      SCON=0x50;

      AUXR=0x40; //设置定时器T1为1T,即一个机器周期模式

      TMOD=0x20;

      TL1=(256-(FOSC/32/BAUD));

      TH1=(256-(FOSC/32/BAUD));

      TR1=1;

      ES=1;

      EA=1;

      SendString("Hello");

      while(1);

}

void Uart() interrupt 4 using 1

{

      if(RI)

      {

             RI=0;

             P0=SBUF;

      }

      if(TI)

      {

             TI=0;

             busy=0;

      }

}

void SendData(BYTE dat)

{

      while(busy);

      busy=1;

      SBUF=dat;

}

void SendString(char *s)

{

      while(*s)

      {

             SendData(*s++);

      }

}


使用特权

评论回复
7
caijie001| | 2018-1-2 23:41 | 只看该作者
哈哈哈,赞,

使用特权

评论回复
8
一路向北lm|  楼主 | 2018-1-3 16:46 | 只看该作者

不用客气

使用特权

评论回复
9
一路向北lm|  楼主 | 2018-1-7 13:29 | 只看该作者

五、 外部中断的使用

#include

sbit L1=P0^0;

int main()

{

   IT0=1; //IT0=1,下降沿触发外部中断0,IT0=0边沿触发

   EX0=1;//使用外部中断0

  EA=1;

  while(1)

{

      

  }

}

void Ex_int0() interrupt 0 //外部中断优先级最高

{

P2=((P2&0x1f)|0x80);

L1=~L1;

P2=(P2&0x1f);

}     

其中,外部中断的引脚控制是P3^2,P3^3,即对应独立按键的S5,S4。


使用特权

评论回复
10
一路向北lm|  楼主 | 2018-1-7 13:30 | 只看该作者

六.实时时钟DS1302的使用

蓝桥杯提供函数,解释为:里面的命令和写入的数据可以看芯片手册:

左侧的READ、WRITE分别是读写的命令,BIT7-BIT0是要写入的数据,根据需要进行配置。DS1302只需记住这两个函数即可:Write_Ds1302( , )与Read_Ds1302(x),配置看手册。

重点:芯片表说明:第一行:秒->因为秒的范围是0-59,所以6,5,4位表示秒的十位,3,2,1,0表示个位,十位最大是5,所以三位即可。

第二行:跟上面一样;

第三行:7位:1为12小时制,0为24小时制;5位:12小时制时为0表示上午,1表示下午,24小时制时,和4位一起表示小时的十位;

其余的时间一样的表示。

倒数第二行:只看7位:为1时禁止写数据,所以开始写数据时必须置0;

读数时:

!!需要加“写操作这一行代码”。

读的话直接按照命令读即可。

DS1302进阶(BCD码转换):解决之前60秒不能进位的问题。

1)写入初始值时,要把10十进制数转换为BCD码,

例:写入时间->17:58:50

Ds1302_Single_Byte_Write(0x8e, 0x00);//写操作

Ds1302_Single_Byte_Write(0x85, ((17/10)<<4 | (17)));//写时

    Ds1302_Single_Byte_Write(0x83, ((58/10)<<4 | (58)));//写分

Ds1302_Single_Byte_Write(0x81, ((50/10)<<4 | (50)));//写秒

Ds1302_Single_Byte_Write(0x8e, 0x80);//写保护

即转换的公式是:((Value/10)<<4 | (Value)),可以写一个settime()函数。

2 ) 读数:读回来的数要进行转换成十进制数

((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);

八进制转十进制->

ReadValue=Ds1302_Single_Byte_Read(0x85);

          hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);

   !!(这句一定不要省)      Ds1302_Single_Byte_Write(0x00, 0x00);//写操作

          ReadValue=Ds1302_Single_Byte_Read(0x83);

          minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);

          Ds1302_Single_Byte_Write(0x00, 0x00);//写操作

          ReadValue=Ds1302_Single_Byte_Read(0x81);

          sec=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);

          Ds1302_Single_Byte_Write(0x00, 0x00);//写操作

显示:

          dspbuf[0]=hour/10;

          dspbuf[1]=hour;

          dspbuf[2]=minute/10;

      dspbuf[3]=minute;

          dspbuf[4]=sec/10;

          dspbuf[5]=sec;


使用特权

评论回复
11
一路向北lm|  楼主 | 2018-1-7 13:31 | 只看该作者

七、 PCF8591与IIC总线的使用

(1)IIC总线的使用:

比赛提供了IIC的两个库文件,IIC.h;IIC.c,其中需要注意的函数是:

其中,该函数是初始化的,当使用AD转换的时候需要在main函数开始时调用,该函数内部只需看这句代码即可:i2c_sendbyte(0x03);//ADC通道3,板上有4个模拟输入口,分别为0,1,2,3;设置哪一个模拟输入口就是根据这句代码,0x03表示通道3,这是根据芯片手册配置的,如图:

8位前6位不用管,都为0,最后两位就是配置选择哪一个通道的。

第二个函数:

读取AD转换后的数值,这个函数直接调用就可以了,函数内部如何实现不用管,但是需要注意的是:该函数扫描调用最好是100ms。

第三个函数,上面的都是AD转换,即模拟信号转数字信号,下面这个函数是DA转换,数字信号转换成模拟信号,就是单片机输出数字信号,用万能表去量单片机引出的引脚,量一下电压大小,这个估计比赛不会考,不过预防万一:

该函数和上面两个函数分离开来的,一、二函数是要在一起使用,初始化后之后才能调用,第三个加入头文件,直接调用即可,比较简单!!

上面说法有误,A/D转换的初始化函数和读取转换后的数值都需要自己写。

这里了解一下PCF8591只需根据时序格式发送地址字节和控制字节: ,这是地址字节,其中A2,A1,A0硬件已经接地,故都为0,最低位表示的是你要从IIC总线上读数还是写数据,1表示读,0表示写,即读数据发的地址是:0x91;写数据发的地址是0x90;

控制字节:

由芯片资料知,控制字节有8位,有两位固定是0,除了第0、1位需要自己设置,其他的我们都设为0,那些位都是一些具体的功能,我们暂时用不着,不用管先,第0、1位是模拟通道选择,PCF8591上提供了4路模拟通道,根据需求进行选择,如选择通道3即发送控制字节:0x03;

地址字节和控制字节都明白了,接下来根据时序要求进行配置,A/D转换需要一个初始化函数:Init_ADpcf8591();和一个获得AD转换后的数值的函数:adc_pcf8591();其中初始化函数的作用是发送AD转换的控制字节;adc_pcf8591()发送读取得地址并读回数据,先写指令才能读;格式如下:

这个是初始化的协议:分别是startIIC、(地址写)发送0x90、等待应答、发送控制字节(AD这里是选择通道的指令,如选择通道3,0x03)0x03、等待应答、(达到目的,没有后续的操作,直接停止总线)StopIIC.

初始化的函数就是如此写;

adc_pcf8591的协议:

依次是:startIIc、发送读地址0x91、等待应答、读回AD转换后的数值、读回后发送应答给PCF8591,表示收到,并且不需要再返回应答,要传参数1,如图红圈示,即函数Ack(1);、最后stopIIC总线。

D/A转换(其实挺麻烦,先前太自信了,哈):

所谓D/A转换其实就是把数字信号转换成模拟信号输出,用单片机发数字通过D/A转换成电压输出,检测的方法可以用电压表测量。

配置的方法跟A/D类似,先发地址字节,再发控制字节,然后把数字发出去(AD这里是接收模拟信号,是相反的机制)。

控制字节:

控制字节的第6位是1的话是模拟输出模式,其余位全为0,发送格式跟AD一样:

(2)EEPROM的使用,AT24C02,可以掉电依旧保存上一次操作的数据,下次上电后接着运行。

需要注意两个函数,一个是写进EEPROM里面保存,再次上电再从里面读回来:

其中写函数需要指定AT24C02的地址以及需要写入的数据,读函数要想取回写进的数据,需要从相同的地址里面读:

其中AT24C02的存储地址是0x00,可以是其他地址,如0x02,但是读和写的地址必须一致。

写与读的协议与AD或DA相同,

由芯片资料及原理图知EEPROM(AT24C02)的写地址为0xa0;读地址为0xa1;注意:读数的时候读出一个数之后发送一个应答信号,若ACK(0)表示还想继续读下一个字节,若ACK(1);则不想再读数,让EEPROM停止发送。


使用特权

评论回复
12
一路向北lm|  楼主 | 2018-1-7 13:33 | 只看该作者

八、DS18B20时钟芯片的使用

比赛有提供代码,只需记住这个函数:

读取温度值,整数(其中,提示EA总中断要打开、关闭,也可以不用)。

浮点数的表示。

注意,只有提供函数,没有提供读取温度的函数,即上面的那个,只有下面: 这几个函数。

编写读取温度的函数需要记住DS13B20的三条指令,0xCC,跳过ROM检测;然后启动温度转换:0x44;转换需要时间,这里精确延时Delay_OneWire(200);然后再次初始化,再次执行跳过,然后读取温度指令:0xBE.;注意读出的温度是低字节先,然后才是高字节,分别用两个变量保存还要通过公式转换成我们需要的整数或浮点数。完整代码如上图示。


使用特权

评论回复
13
一路向北lm|  楼主 | 2018-1-7 13:33 | 只看该作者

九.超声波传感器的使用

#include "reg52.h"  //定义51单片机特殊功能寄存器

#include "intrins.h"

#include "absacc.h"

//12M用这个

//11.0592用这个

#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();

                 _nop_();_nop_();}

sbit TX = P1^0;  //发射引脚

sbit RX = P1^1;  //接收引脚

code unsigned char tab[] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\

                             0xff};

unsigned char dspbuf[8] = {10,10,10,10,10,10,10,10};  //显示缓冲区

unsigned char dspcom = 0;

unsigned int intr = 0;

bit s_flag;

unsigned int t = 0;

void send_wave(void);

void display(void);

void main(void)

{

    unsigned int distance;

    TMOD |= 0x11;  //配置定时器工作模式

    TH0 = (65536-2000)/256;

    TL0 = (65536-2000)%6;

    TH1 = 0;

    TL1 = 0;

    EA = 1;

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

    TR0 = 1;  //启动定时器  

    while(1){

      

        if(s_flag)

        {

            s_flag = 0;

           

                      t = TH1;

                      t <<= 8;

                      t |= TL1;

                      distance = (unsigned int)(t*0.017);  //计算距离                          

               }

               TH1 = 0;

               TL1 = 0;

        }

      

                    

        dspbuf[5] = distance/100;

        dspbuf[6] = distance0/10;

        dspbuf[7] = distance;      

    }

}

//定时器0中断服务函数

void isr_timer_0(void)  interrupt 1  //默认中断优先级 1

{

    TH0 = (65536-2000)/256;

    TL0 = (65536-2000)%6;  //定时器重载

   

display();  //2ms执行一次

if(++intr == 200){

        s_flag = 1;

        intr = 0;

    }

}

//显示函数

void display(void){

       XBYTE[0xE000] = 0xff;  //去除鬼影

       XBYTE[0xC000] = (1<<dspcom);

       XBYTE[0xE000] = tab[dspbuf[dspcom]];

if(++dspcom == 8){

              dspcom = 0;

}     

}

//TX引脚发送40KHz方波信号驱动超声波发送探头

void send_wave(void)

{

unsigned char i = 8;  //发送8个脉冲

do

{

        TX = 1;

        somenop;

        TX = 0;

        somenop;

}

while(i--);

}

必要时还可以加个看门狗:   WDT_CONTR=0x34;


使用特权

评论回复
14
一路向北lm|  楼主 | 2018-1-7 13:35 | 只看该作者

十、步进电机与直流电机的使用

参考代码如下:

#include

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

sbit B1=P1^3;

sbit C1=P1^2;

sbit D1=P1^1;

void qudong1();

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

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

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

#define Dy_D1 {A1=0;B1=0;C1=0;D1=1;}//D相通电,其他相断电    //采用1相励磁

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

unsigned char Speed,Speed1;

void DelayUs2x(unsigned char t)

{  

while(--t);

}

void DelayMs(unsigned char t)

{

   

while(t--)

{

     //大致延时1mS

     DelayUs2x(245);

    DelayUs2x(245);

}

}

main()

{

Dy_OFF;

for(;;)

{

   qudong1();

  }

}

void qudong1()

{

unsigned int i=470;//旋转一周时间

  Speed=5;

  while(i--)  //正向

  {        

     Dy_A1               

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

     DelayMs(Speed);        

//改变这个参数可以调整电机转速 ,

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

     Dy_B1                               //顺序从A1--D1相通电如果为正转,那么顺序从D1--A1相通电则为反转

     DelayMs(Speed);

     Dy_C1

     DelayMs(Speed);

     Dy_D1

     DelayMs(Speed);

  }

Dy_OFF

  i=512;

  while(i--)//反向

  {

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

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

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

     Dy_C1

     DelayMs(Speed);

     Dy_B1

     DelayMs(Speed);

     Dy_A1

     DelayMs(Speed);

  }        

}

直流电机:

#include

#define uint unsigned int

void drive();

void delay(uint);

sbit dj1=P1^0; //电机,1引脚

uint set; //set为电机转角标志位

unsigned char angle,angle1;   //angle为电机PWM变化打角

void Time0_Init()       //中断初始化

{

TMOD=0X01;

IE=0X82;

TH0=(65536-58)/256;           

TL0=(65536-58)%6;

TR0=1;

}

void main()         //主函数

{

set=0;

angle=62;  // 改变angle的值可以改变电机的占空比

Time0_Init();

  for(;;)

   {

    }     

}

void T0_time()interrupt 1

{

TH0=(65536-58)/256;           

TL0=(65536-58)%6;

  if(set

   dj1=1;

else

  dj1=0;

set++;

if(set>165) set=0;   //电机占空比

}


使用特权

评论回复
15
一路向北lm|  楼主 | 2018-1-7 13:35 | 只看该作者

十一、 扩展:宏定义编程方法

常用的可以宏定义,省时,下面以数码管为例:

#define rst573 P2&=0x1f

#define Y6C P2=   ((P2&0x1f)|0xc0)

#define Y7C P2=   ((P2&0x1f)|0xe0)

code unsigned char tab[] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};

unsigned char dspbuf[8] = {10,10,10,10,10,10,10,10};  //显示缓冲区

unsigned char dspcom;

unsigned char flag;

void display()

{

Y7C;

P0=0xff;

rst573;

Y6C;

P0=1<<dspcom;

rst573;

Y7C;

P0=tab[dspbuf[dspcom]];

rst573;

if(++dspcom==8)

        dspcom=0;

}




使用特权

评论回复
16
ohy3686| | 2018-1-27 22:35 | 只看该作者
一路向北lm 发表于 2017-12-30 12:06
4.矩阵键盘矩阵键盘需要死记了!这里不再讲独立键盘。第二种单片机键盘扫描代码(没有消抖):sfr P4^4=0xC0 ...

sbit c1=P4^4;
sbit c2=P4^2;
这个代码不是89C52的吗?
51单片机是没有P4.2和P4.4的哦。

使用特权

评论回复
17
山东电子小菜鸟| | 2018-1-28 11:41 | 只看该作者
感谢 分享

使用特权

评论回复
18
lzdestiny| | 2018-10-19 15:33 | 只看该作者
楼主辛苦了

使用特权

评论回复
19
一路向北lm|  楼主 | 2018-10-19 21:47 | 只看该作者

不客气的,帮助需要的人。

使用特权

评论回复
20
思难忘| | 2020-4-2 18:14 | 只看该作者
谢谢分享

使用特权

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

本版积分规则

275

主题

3784

帖子

76

粉丝