圈圈.第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、

浙公网安备 33010602011771号