圈圈.第2章代码

1、main.c

#include <AT89X52.H>

/*
void main()
{
    P2 = 0;
    while (1)
    {}
}
//*/

/*
#include "Key.h"
#include "Led.h"
void main()
{
    EA = 1;
    InitKeyboard();
    while(1)
    {
        LEDs = ~KeyPress;
    }
}
//*/


//*
#include "Key.h"
#include "Led.h"
#include "UART.h"
#include "pdiusbd12.h"

code uint8 HeadTable[][74]={
"********************************************************************\r\n",
"******          《圈圈教你玩USB》之 学习板测试程序            ******\r\n",
"******                      AT89S52 CPU                       ******\r\n",
"******                  建立日期:",__DATE__,"                 ******\r\n",
"******                   建立时间:",__TIME__,"                   ******\r\n",
"******                    作者:电脑圈圈                      ******\r\n",
"******                    欢迎访问作者的                      ******\r\n",
"******           USB专区:http://group.ednchina.com/93/       ******\r\n",
"******      BLOG1:http://www.ednchina.com/blog/computer00    ******\r\n",
"******                BLOG2:http://computer00.21ic.org       ******\r\n",
"******                  请按K1-K8分别进行测试                 ******\r\n",
"********************************************************************\r\n",
};

//********************************************************************
//  函数功能:主函数。
//  入口参数:无。
//  返    回:无。
//  备    注:无。
//********************************************************************
void main(void)  //主函数
{
    uint8 i;
    uint16 id;
    
    EA = 1; //打开中断
    InitKeyboard(); //初始化按键
    InitUART();  //初始化串口
    
    for(i=0; i<16; i++)      //显示信息
    {
        Prints(HeadTable[i]);
    }
    
    id = D12ReadID();
    
    Prints("Your D12 chip\'s ID is: ");
    PrintShortIntHex(id);
    
    if (id == 0x1012)
    {
        Prints(". ID is correct! Congratulations!\r\n\r\n");
    }
    else
    {
        Prints(". ID is incorrect! What a pity!\r\n\r\n");
    }
    
    while(1)  //死循环
    {
        LEDs = ~KeyPress;  //将按键结果取反后控制LED
        if (KeyDown)          //有键按下
        {              //处理按下的键
            if (KeyDown & KEY1)
            {
                Prints("KEY1 down\r\n");
                KeyDown &= ~KEY1;
            }
            if (KeyDown & KEY2)
            {
                Prints("KEY2 down\r\n");
                KeyDown &= ~KEY2;
            }
            if (KeyDown & KEY3)
            {
                Prints("KEY3 down\r\n");
                KeyDown &= ~KEY3;
            }
            if (KeyDown & KEY4)
            {
                Prints("KEY4 down\r\n");
                KeyDown &= ~KEY4;
            }
            if (KeyDown & KEY5)
            {
                Prints("KEY5 down\r\n");
                KeyDown &= ~KEY5;
            }
            if (KeyDown & KEY6)
            {
                Prints("KEY6 down\r\n");
                KeyDown &= ~KEY6;
            }
            if (KeyDown & KEY7)
            {
                Prints("KEY7 down\r\n");
                KeyDown &= ~KEY7;
            }
            if (KeyDown & KEY8)
            {
                Prints("KEY8 down\r\n");
                KeyDown &= ~KEY8;
            }
        }
        
        if (KeyUp)//有键释放
        {//处理释放的键
            if (KeyUp & KEY1)
            {
                Prints("KEY1 up\r\n");
                KeyUp &= ~KEY1;
            }
            if (KeyUp & KEY2)
            {
                Prints("KEY2 up\r\n");
                KeyUp &= ~KEY2;
            }
            if (KeyUp & KEY3)
            {
                Prints("KEY3 up\r\n");
                KeyUp &= ~KEY3;
            }
            if (KeyUp & KEY4)
            {
                Prints("KEY4 up\r\n");
                KeyUp &= ~KEY4;
            }
            if (KeyUp & KEY5)
            {
                Prints("KEY5 up\r\n");
                KeyUp &= ~KEY5;
            }
            if (KeyUp & KEY6)
            {
                Prints("KEY6 up\r\n");      
                KeyUp &= ~KEY6;
            }
            if (KeyUp & KEY7)
            {
                Prints("KEY7 up\r\n");
                KeyUp &= ~KEY7;
            }
            if (KeyUp & KEY8)
            {
                Prints("KEY8 up\r\n");
                KeyUp &= ~KEY8;
            }
        }
    }
}// main
////////////////////////End of function//////////////////////////////
//*/

 

2、Key

  2.1、Key.c

#include "Key.h"
#include "MyType.h"
#include "config.h"

//volatile uint8 idata KeyCurrent,KeyOld,KeyNoChangedTime;
//volatile uint8 idata KeyPress;
//volatile uint8 idata KeyDown,KeyUp,KeyLast;
volatile uint8 idata KeyCurrent, KeyOld, KeyLast, KeyNoChangedTime;// ZC: 扫描按键使用的变量,应用程序不直接使用它们
volatile uint8 idata KeyPress,   KeyDown, KeyUp;// ZC: 提供给应用程序使用的变量
volatile uint8  KeyCanChange;// ZC: 提供给应用程序使用的变量。应用程序用来控制是否允许新的扫描

/********************************************************************
函数功能:定时器0初始化,用来做键盘扫描。
入口参数:无。
返    回:无。
备    注:无。
********************************************************************/
void InitTimer0(void)
{
    TMOD &= 0xF0;// 定时器的低4位是 控制定时器0 的,先置为0          // ZC: TMOD = 0x89;
    TMOD |= 0x01;// 然后再将最低位设置为1,最终选择16位定时器模式
    ET0 = 1;// 允许定时器0中断                                      // ZC: ET0 = 0xA9;/* 1=Enable Timer 0 interrupt */
    TR0 = 1;// 启动定时器0                                          // ZC: TR0 = 0x8C;
}
/*******************************************************************/


/********************************************************************
函数功能:键盘初始化
入口参数:无。
返    回:无。
备    注:无。
********************************************************************/
void InitKeyboard(void)
{
    KeyIO=0xFF;//键盘对应的口设置为输入状态     // ZC: ==>P1
    KeyPress=0;//无按键按下                        // ZC: volatile uint8 idata
    KeyNoChangedTime=0;//按键按下状态未改变的时间 (ZC:设置)为0 // ZC: volatile uint8 idata
    KeyOld=0; //上一次按键值为0(没有按键按下)    // ZC: volatile uint8 idata
    KeyCurrent=0;//当前按键值为0(没有按键按下)    // ZC: volatile uint8 idata
    KeyLast=0;//最后一次按键值为0(没有按键按下)    // ZC: volatile uint8 idata
    KeyDown=0;//没有按键按下                    // ZC: volatile uint8 idata
    KeyUp=0;//没有按键释放                        // ZC: volatile uint8 idata
    InitTimer0();//初始化定时器
    KeyCanChange=1;//允许键值改变                // ZC: volatile uint8
}
/*******************************************************************/

/********************************************************************
函数功能:定时器0中断处理。
入口参数:无。
返    回:无。
备    注:22.1184M晶体约5ms中断一次。
********************************************************************/
// ZC: 1号中断 的中断例程
// ZC: 书P49(Pdf.P62)说"中断函数不能有入口参数也不能有返回参数",意思是 不能有传入参数和返回值??
void Timer0Isr(void) interrupt 1
{ 
    //定时器0重装,定时间隔为5ms,加15是为了修正重装所花费时间
    //这个值可以通过软件仿真来确定,在这里设置断点,调整使两次运行时间差刚好为5ms即可。
    // ZC: "重装"是什么意思?下面2个值设置是干嘛用的?设置定时器的延时时间?
    TH0 = (65536 - Fclk /1000 /12 *5 + 15) / 256;// ZC: Fclk --> 22118400UL /*使用22.1184M晶体*/     
    TL0 = (65536 - Fclk /1000 /12 *5 + 15) % 256;
    
    if(!KeyCanChange)
        return;     //如果正在处理按键,则不再扫描键盘 
    
    //开始键盘扫描
    //保存按键状态到当前按键情况
    //KeyCurrent总共有8个bit
    //当某个开关按下时,对应的bit为1
    KeyCurrent = GetKeyValue(); //读取键值,GetKeyValue()其实是个宏,不是函数,
                                //这里故意写成函数的样子,美观。它的定义在key.h文件中
    
    if(KeyCurrent != KeyOld) //如果两次值不等,说明按键情况发生了改变
    {
        KeyNoChangedTime = 0;       //键盘按下时间为0
        KeyOld = KeyCurrent;        //保存当前按键情况
        return;
    }
    else// ZC: 两次值相等 --> 按键情况 未改变
    {
        KeyNoChangedTime ++;         //按下时间累计
        if(KeyNoChangedTime >= 1)     //如果按下时间足够
        {
            KeyNoChangedTime = 1;
            KeyPress = KeyOld;       //保存按键
            KeyDown |= (~KeyLast) & (KeyPress);//求出新按下的键
            KeyUp |= KeyLast & (~KeyPress);    //求出新释放的键
            KeyLast = KeyPress;                   //保存当前按键情况
        }
    }
}
/*******************************************************************/

  2.2、Key.h

#ifndef __KEY_H__
#define __KEY_H__

#include <at89x52.h>
#include "MyType.h"

extern volatile uint8 idata KeyCurrent,KeyOld,KeyNoChangedTime;
extern volatile uint8 idata KeyPress;
extern volatile uint8 idata KeyDown,KeyUp,KeyLast;

extern volatile uint8 KeyCanChange;

void InitKeyboard(void);

#define KeyIO P1
//获取按键值的宏。由于开关按下为0,所以对结果取反
#define GetKeyValue() (~KeyIO)

#define KEY1 0x01
#define KEY2 0x02
#define KEY3 0x04
#define KEY4 0x08
#define KEY5 0x10
#define KEY6 0x20
#define KEY7 0x40
#define KEY8 0x80

#endif

 

3、UART

  3.1、UART.c

#include <at89x52.H>

#include "UART.h"
#include "MyType.h"
#include "config.h"


volatile uint8 Sending;


/********************************************************************
函数功能:串口初始化。
入口参数:无。
返    回:无。
备    注:无。
********************************************************************/
void InitUART(void)
{
    EA = 0;       //暂时关闭中断           // ZC: EA = 0xAF; /* 0=Disable all interrupts */
    TMOD &= 0x0F; //定时器1模式控制在高4位 // ZC: TMOD = 0x89;
    TMOD |= 0x20; //定时器1工作在模式2,自动重装模式
    SCON = 0x50;  //串口工作在模式1 // ZC: SCON = 0x98;
    TH1 = 256 - Fclk /(BitRate*12*16);//计算定时器重装值 // ZC: H1 = 0x8D;
    TL1 = 256 - Fclk /(BitRate*12*16);                      // ZC: TL1 = 0x8B;
    PCON |= 0x80;//串口波特率加倍    // ZC: PCON = 0x87;
    ES = 1;        //串行中断允许        // ZC: ES = 0xAC; /* 1=Enable Serial port interrupt */
    TR1= 1;     //启动定时器1        // ZC: TR1 = 0x8E;
    REN= 1;     //允许接收            // ZC: REN = 0x9C;
    EA = 1;      //允许中断
}
////////////////////////End of function//////////////////////////////

/********************************************************************
函数功能:串口中断处理。
入口参数:无。
返    回:无。
备    注:无。
********************************************************************/
// 串口的中断号是4
// 这个驱动只发送数据,∴接收到数据就不管它了,只是简单的将中断标志清除即可。
//    ZC: 接收到的数据(如果接收到的话) 不用做任何处理?如何得到接收到的数据?
// 而数据发送中断,也比较简单,清除中断标志后再将一个正在发送状态的变量清除即可。
// 正在发送状态的标志需要自己增加一个变量。
void UartISR(void) interrupt 4
{
    if(RI)    //收到数据 // RI = 0x98;
    {
        RI=0;   //清中断请求
    }
    else      //发送完一字节数据
    {
        TI=0;  // ZC: TI = 0x99;
        Sending=0;  //清正在发送标志
    }
}
////////////////////////End of function//////////////////////////////

/********************************************************************
函数功能:往串口发送一字节数据。
入口参数:d: 要发送的字节数据。
返    回:无。
备    注:无。
********************************************************************/
void UartPutChar(uint8 d)
{
    SBUF = d; //将数据写入到串口缓冲
    Sending = 1;     //设置发送标志
    while(Sending); //等待发送完毕
}
////////////////////////End of function//////////////////////////////

/********************************************************************
函数功能:发送一个字符串。
入口参数:pd:要发送的字符串指针。
返    回:无。
备    注:无。
********************************************************************/
void Prints(uint8 * pd)
{
    while( (*pd) != '\0' ) //发送字符串,直到遇到0才结束
    {
        UartPutChar(*pd); //发送一个字符
        pd ++;  //移动到下一个字符
    }
}
////////////////////////End of function//////////////////////////////

/********************************************************************
函数功能:将整数转按十进制字符串发送。
入口参数:x:待显示的整数。
返    回:无。
备    注:无。
********************************************************************/
/*
void PrintLongInt(uint32 x)
{
    int8 i;
    uint8 display_buffer[10];
    
    for(i=9; i>=0; i--)
    {
        display_buffer[i] = '0' + x%10;
        x /= 10;
    }
    for(i=0; i<9; i++)
    {
        if(display_buffer[i]!='0')break;
    }
    for(; i<10; i++)
        UartPutChar( display_buffer[i] );
}
//*/
////////////////////////End of function//////////////////////////////

code uint8 HexTable[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
/********************************************************************
函数功能:将短整数按十六进制发送。
入口参数:待发送的整数。
返    回:无。
备    注:无。
********************************************************************/
void PrintShortIntHex(uint16 x)
{
    uint8 i;
    uint8 display_buffer[7];
        display_buffer[6] = 0;
        display_buffer[0] = '0';
        display_buffer[1] = 'x';
    for(i=5; i>=2; i--) //将整数转换为4个字节的HEX值
    {
        display_buffer[i] = HexTable[(x & 0xf)];
        x >>= 4;
    }
    Prints(display_buffer);
}
////////////////////////End of function//////////////////////////////

/********************************************************************
函数功能:将长整数按十六进制发送。
入口参数:待发送的整数。
返    回:无。
备    注:无。
********************************************************************/
/*
void PrintLongIntHex(uint32 x)  //
{
    uint8 i;
    uint8 display_buffer[11];
        display_buffer[10] = 0;
        display_buffer[0] = '0';
        display_buffer[1] = 'x';
    for(i=9; i>=2; i--)
    {
            display_buffer[i ] =HexTable[( x &0xf)];
             x>> =4;
    }
    Prints(display_buffer);
}
//*/
////////////////////////End of function//////////////////////////////


/********************************************************************
函数功能:发送一个byte的数据。
入口参数:待发送的数据。
返    回:无。
备    注:无。
********************************************************************/
/*
void Printc(uint8 x)
{
    Sending = 1;
    SBUF = x;
    while(Sending);
}
//*/
////////////////////////End of function//////////////////////////////


/********************************************************************
函数功能:以HEX格式发送一个byte的数据。
入口参数:待发送的数据
返    回:无。
备    注:无。
********************************************************************/
/*
void PrintHex(uint8 x)
{
    Printc('0');
    Printc('x');
    Printc(HexTable[x >> 4]);
    Printc(HexTable[x & 0xf]);
    Printc(' ');
}
//*/
////////////////////////End of function//////////////////////////////

  3.2、UART.h

#ifndef __UART_C__
#define __UART_C__

#include "MyType.h"

void InitUART(void);
void UartPutChar(uint8);
void Prints(uint8 *);
void PrintLongInt(uint32);
void PrintShortIntHex(uint16 x);
void PrintLongIntHex(uint32);
void Printc(uint8);
void PrintHex(uint8 x);

#endif

 

4、PDIUSBD12

  4.1、PDIUSBD12.c

#include <AT89x52.H>
#include "MyType.h"
#include "PDIUSBD12.H"


/********************************************************************
函数功能:D12写命令。
入口参数:Command:一字节命令。
返    回:无。
备    注:无。
********************************************************************/
void D12WriteCommand(uint8 Command)
{
 D12SetCommandAddr();  //设置为命令地址
 D12ClrWr(); //WR置低
 D12SetPortOut(); //将数据口设置为输出状态(注意这里为空宏,移植时可能有用)
 D12SetData(Command);  //输出命令到数据口上
 D12SetWr(); //WR置高
 D12SetPortIn(); //将数据口设置为输入状态,以备后面输入使用
}
////////////////////////End of function//////////////////////////////

/********************************************************************
函数功能:读一字节D12数据。
入口参数:无。
返    回:读回的一字节。
备    注:无。
********************************************************************/
uint8 D12ReadByte(void)
{
 uint8 temp;
 D12SetDataAddr(); //设置为数据地址
 D12ClrRd(); //RD置低
 temp=D12GetData(); //读回数据
 D12SetRd(); //RD置高
 return temp; //返回读到数据
}
////////////////////////End of function//////////////////////////////

/********************************************************************
函数功能:读D12的ID。
入口参数:无。
返    回:D12的ID。
备    注:无。
********************************************************************/
uint16 D12ReadID(void)
{
 uint16 id;
 D12WriteCommand(Read_ID); //写读ID命令
 id=D12ReadByte(); //读回ID号低字节
 id|=((uint16)D12ReadByte())<<8; //读回ID号高字节
 return id;
}
////////////////////////End of function//////////////////////////////

  4.2、PDIUSBD12.h

#ifndef __PDIUSBD12_H__
#define __PDIUSBD12_H__

#include <at89x52.h>
#include "MyType.h"

//命令地址和数据地址
#define D12_COMMAND_ADD           1
#define D12_DATA_ADD              0

//PDIUSBD12芯片连接引脚
#define D12_DATA                  P0
#define D12_A0                    P3_5
#define D12_WR                    P3_6
#define D12_RD                    P3_7
#define D12_INT                   P3_2

//选择命令或数据地址
#define D12SetCommandAddr() D12_A0=D12_COMMAND_ADD
#define D12SetDataAddr()    D12_A0=D12_DATA_ADD
//WR控制
#define D12SetWr() D12_WR=1
#define D12ClrWr() D12_WR=0
//RD控制
#define D12SetRd() D12_RD=1
#define D12ClrRd() D12_RD=0
//获取中断状态
#define D12GetIntPin()  D12_INT
//读写数据
#define D12GetData() D12_DATA
#define D12SetData(Value) D12_DATA=(Value)

//将数据口设置为输入状态,51单片机端口写1就是为输入状态
#define D12SetPortIn() D12_DATA=0xFF

//将数据口设置为输出状态,由于51单片机是准双向IO口,所以不用切换,为空宏
#define D12SetPortOut()

//D12的读ID命令
#define Read_ID                  0xFD

//函数声明
void D12WriteCommand(uint8);
uint8 D12ReadByte(void);
uint16 D12ReadID(void);

#endif

 

5、config.h

#ifndef __CONFIG_H__
#define __CONFIG_H__

// UL --> 表示无符号长整型
// 因为默认是整型,(ZC: 又∵)Keil C51中整数是2个字节的,最大只能到65536,这里已经超过,因而需要增加UL,表示长整。
#define Fclk      22118400UL         /*使用22.1184M晶体*/ // 时钟频率
#define BitRate   9600UL             /*波特率定义为9600*/

#endif

 

6、Led.h

#ifndef __LED_H__
#define __LED_H__

//全部LED
#define LEDs  P2

//单个LED,LED1~LED7
//注意“^”这个操作符,只有跟sbit搭配时才表示定义一个位,
//C语言中,“^”表示异或操作,不要在程序中直接使用 “^”来表示某一位。
sbit LED1  =     LEDs^0;
sbit LED2  =     LEDs^1;
sbit LED3  =     LEDs^2;
sbit LED4  =     LEDs^3;
sbit LED5  =     LEDs^4;
sbit LED6  =     LEDs^5;
sbit LED7  =     LEDs^6;
sbit LED8  =     LEDs^7;

//点亮某个LED
#define OnLed1()  LED1=0
#define OnLed2()  LED2=0
#define OnLed3()  LED3=0
#define OnLed4()  LED4=0
#define OnLed5()  LED5=0
#define OnLed6()  LED6=0
#define OnLed7()  LED7=0
#define OnLed8()  LED8=0

//关闭某个LED
#define OffLed1() LED1=1
#define OffLed2() LED2=1
#define OffLed3() LED3=1
#define OffLed4() LED4=1
#define OffLed5() LED5=1
#define OffLed6() LED6=1
#define OffLed7() LED7=1
#define OffLed8() LED8=1

#endif// __LED_H__

 

7、MyType.h

#ifndef __MY_TYPE_H__
#define __MY_TYPE_H__

#define uint8    unsigned char
#define uint16   unsigned short int
#define uint32   unsigned long int
#define int8     signed char
#define int16    signed short int
#define int32    signed long int
#define uint64   unsigned long long int
#define int64    signed long long int

#endif

 

8、

9、

10、

 

posted @ 2018-02-28 14:22  DanPianJi  阅读(188)  评论(0)    收藏  举报