《圈圈教你玩USB》 第二章 USB 硬件系统设计_测试程序的编写和调试——看书笔记
2017-03-15 21:40
429 查看
2.11测试程序的编写和调试
2.11.4按键驱动的编写
考虑到以后程序的方便性,这里使用定时器中断方式来扫描按键。定时器每隔5ms中断一次,即每5ms扫描一次键盘。
key.c
1)先初始化好一个定时器,此处选择定时器0作为按键扫描的定时器,而定时器1留作串口波特率发生器。初始化定时器就是设置定时器的工作模式,启动定时器等。
//定时器0初始化,用来做按键扫描
voidInitTimer0(void)
{
TMOD&=0xF0;//定时器低4位是控制定时器0的,先置0
TMOD|=0x01;//然后将最低位置1,最终选择16位定时器模式
ET0=1;//允许定时器0中断
TR0=1;//启动定时器0
}
2)再初始化键盘
volatileuint8idataKeyCurrent,KeyOld,KeyNoChangedTime;
volatileuint8idataKeyPress;
volatileuint8idataKeyDown,KeyUp,KeyLast;
volatileuint8KeyCanChange;
//函数功能:键盘初始化
voidInitKeyboard(void)
{
KeyIO=0xFF; //键盘对应的口设置为输入状态
KeyPress=0; //无按键按下
KeyNoChangedTime=0;
KeyOld=0;
KeyCurrent=0;
KeyLast=0;
KeyDown=0;
KeyUp=0;
InitTimer0();//初始化定时器
KeyCanChange=1;//允许键值改变
}
KeyCurrent、KeyOld、KeyLast和KeyNoChangedTime是扫描按键使用的变量,应用程序不直接使用它们。
KeyPress、KeyDown、KeyUp、KeyCanChange是提供给应用程序使用的变量。
KeyPress表示当前被按住不放的键;
KeyDown表示新按下的键;
KeyUp表示心松开的键;
KeyCanChange是应用程序用来控制是否允许新的扫描。
当某个按键被按下时,KeyPress对应位被置1,并且KeyDown对应位也置1;当按键松开后,KeyPress对应
位为0,KeyUp对应位被置1。
3)定时器0中断处理
//函数功能:定时器0中断处理。
//22.1184M晶体约5ms中断一次。
voidTimer0Isr(void)interrupt1
{
//定时器0重装,定时间隔为5ms,加15是为了修正重装所花费时间
//这个值可以通过软件仿真来确定,在这里设置断点,调整使两次运行
//时间差刚好为5ms即可。
TH0=(65536-Fclk/1000/12*5+15)/256;
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
{
KeyNoChangedTime++; //按下时间累计
if(KeyNoChangedTime>=1) //如果按下时间足够
{
KeyNoChangedTime=1;
KeyPress=KeyOld;//保存按键
KeyDown|=(~KeyLast)&(KeyPress);//求出新按下的键
KeyUp|=KeyLast&(~KeyPress);//求出新释放的键
KeyLast=KeyPress; //保存当前按键情况
}
}
}
2.11.5串口驱动的编写
1.串口驱动的重要性:
调试时,在对应位置打印出信息,可以知道程序走过哪些步骤;
2.usart.c
在使用串口之前,必须对串口进行初始化。//函数功能:串口初始化
voidInitUART(void)
{
EA=0; //暂时关闭中断
TMOD&=0x0F; //定时器1模式控制在高4位
TMOD|=0x20;//定时器1工作在模式2,自动重装模式
SCON=0x50;//串口工作在模式1
TH1=256-Fclk/(BitRate*12*16);//计算定时器重装值
TL1=256-Fclk/(BitRate*12*16);
PCON|=0x80;//串口波特率加倍
ES=1;//串行中断允许
TR1=1;//启动定时器1
REN=1;//允许接收
EA=1;//允许中断
}
串口中断处理函数
volatileuint8Sending;
//函数功能:串口中断处理。
voidUartISR(void)interrupt4
{
if(RI)//收到数据
{
RI=0;//清中断请求,因为这里只发送,不接受,故此处只要清除中断标志即可
}
else//发送完一字节数据
{
TI=0;
Sending=0;//清正在发送标志
}
}
发送单个字符函数
//函数功能:往串口发送一字节数据。
//入口参数:d:要发送的字节数据。
voidUartPutChar(uint8d)
{
SBUF=d;//将数据写入到串口缓冲
Sending=1; //设置发送标志
while(Sending);//等待发送完毕
}
发送一个字符串函数
//函数功能:发送一个字符串。
//入口参数:pd:要发送的字符串指针。
voidPrints(uint8*pd)
{
while((*pd)!='\0')//发送字符串,直到遇到0才结束
{
UartPutChar(*pd);//发送一个字符
pd++; //移动到下一个字符
}
}
以HEX格式发送一个整数
codeuint8HexTable[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
//函数功能:将短整数按十六进制发送。
//入口参数:待发送的整数。
voidPrintShortIntHex(uint16x)
{
uint8i;
uint8display_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);
}
2.11.6PDIUSBD12读写函数和读ID的实现
1.读D12的ID号的目的
知道D12是否正常工作
2.PDIUSBD12的读写时序图
分析:CS_N是片选信号。上图所示,只有片选信号拉低时,下面的操作才有意义。
A0是地址线,用于选择是命令还是数据。A0为1时,表示操作的是命令;A0为0时,表示操作的是数据。
WR_N是写信号,表示WR_N的上升沿将数据写入芯片中。数据必须在上升沿的前后稳定地保持一段时
间(即图中的tWDSU和tWDH)才能可靠写入。
RD_N是读选通信号,在读数据时,先将RD_N置低,等待tRLDD时间后,数据将出现在数据总线DATA
[7:0]上,这时可以读取数据。读取完后,将RD_N拉高,数据在总线上的数据将在tRHDZ时间后消失。
3.PDIUSBD12.c
根据上面的分析,可以得出:写命令的操作过程为:先将A0置高(即设置为命令状态),再讲WR_N置低,把需要发送的命令放到数据总线上,
再讲WR_N置高。这样将产生一个上升沿,从而把数据写入了D12中。写完后,须将总线设置为输入状态,以避免
总线冲突。
写数据的操作过程为:只要将上面的A0设置为低即可(设置为数据状态)。
//函数功能:D12写命令。
//入口参数:Command:一字节命令。
voidD12WriteCommand(uint8Command)
{
D12SetCommandAddr();//设置为命令地址
D12ClrWr(); //WR置低
D12SetPortOut(); //将数据口设置为输出状态(注意这里为空宏,移植时可能有用)
D12SetData(Command); //输出命令到数据口上
D12SetWr(); //WR置高
D12SetPortIn(); //将数据口设置为输入状态,以备后面输入使用
}
读一个字节的操作过程为:先将A0置低(即设置为数据状态),再将RD_N置低(表示读数据),读取P0口上的数据
并保存,最后将RD_N置高,结束读过程。最后函数返回读取到的数据。
//函数功能:读一字节D12数据。
//返回:读回的一字节。
uint8D12ReadByte(void)
{
uint8temp;
D12SetDataAddr();//设置为数据地址
D12ClrRd(); //RD置低
temp=D12GetData();//读回数据
D12SetRd(); //RD置高
returntemp; //返回读到数据
}
读取2字节的ID号
//函数功能:读D12的ID。
//返回:D12的ID。
uint16D12ReadID(void)
{
uint16id;
D12WriteCommand(Read_ID); //写读ID命令
id=D12ReadByte(); //读回ID号低字节
id|=((uint16)D12ReadByte())<<8; //读回ID号高字节
returnid;
}
4.修改main函数
在main.c中增加读取并显示ID号的代码,检验芯片是否焊接正确。
main.c
/********************************************************************
函数功能:主函数。
入口参数:无。
返回:无。
备注:无。
********************************************************************/
voidmain(void)//主函数
{
uint8i;
uint16id;
EA=1;//打开中断
InitKeyboard();//初始化按键
InitUART();//初始化串口
for(i=0;i<16;i++) //显示信息
{
Prints(HeadTable[i]);
}
id=D12ReadID();
Prints("YourD12chip\'sIDis:");
PrintShortIntHex(id);
if(id==0x1012)
{
Prints(".IDiscorrect!Congratulations!\r\n\r\n");
}
else
{
Prints(".IDisincorrect!Whatapity!\r\n\r\n");
}
while(1)//死循环
{
LEDs=~KeyPress;//将按键结果取反后控制LED
if(KeyDown) //有键按下
{//处理按下的键
if(KeyDown&KEY1)
{
Prints("KEY1down\r\n");
KeyDown&=~KEY1;
}
if(KeyDown&KEY2)
{
Prints("KEY2down\r\n");
KeyDown&=~KEY2;
}
if(KeyDown&KEY3)
{
Prints("KEY3down\r\n");
KeyDown&=~KEY3;
}
if(KeyDown&KEY4)
{
Prints("KEY4down\r\n");
KeyDown&=~KEY4;
}
if(KeyDown&KEY5)
{
Prints("KEY5down\r\n");
KeyDown&=~KEY5;
}
if(KeyDown&KEY6)
{
Prints("KEY6down\r\n");
KeyDown&=~KEY6;
}
if(KeyDown&KEY7)
{
Prints("KEY7down\r\n");
KeyDown&=~KEY7;
}
if(KeyDown&KEY8)
{
Prints("KEY8down\r\n");
KeyDown&=~KEY8;
}
}
if(KeyUp)//有键释放
{//处理释放的键
if(KeyUp&KEY1)
{
Prints("KEY1up\r\n");
KeyUp&=~KEY1;
}
if(KeyUp&KEY2)
{
Prints("KEY2up\r\n");
KeyUp&=~KEY2;
}
if(KeyUp&KEY3)
{
Prints("KEY3up\r\n");
KeyUp&=~KEY3;
}
if(KeyUp&KEY4)
{
Prints("KEY4up\r\n");
KeyUp&=~KEY4;
}
if(KeyUp&KEY5)
{
Prints("KEY5up\r\n");
KeyUp&=~KEY5;
}
if(KeyUp&KEY6)
{
Prints("KEY6up\r\n");
KeyUp&=~KEY6;
}
if(KeyUp&KEY7)
{
Prints("KEY7up\r\n");
KeyUp&=~KEY7;
}
if(KeyUp&KEY8)
{
Prints("KEY8up\r\n");
KeyUp&=~KEY8;
}
}
}
}
如果一切正确,在串口调试助手上(波特率9600数据位8停止位1无硬件流控制)将会显示如下所示信息。
其中日期和时间可能不一样,这取决于当前的编译时间。
2.12本章小结
本章内容的必要性
相关文章推荐
- 【Linux C调试笔记】Linux系统下借助mcheck实现c/c++程序的堆内存异常检查
- linux学习笔记-读《Linux设备驱动开发详解》~第二章 驱动设计的硬件基础
- 今天在硬件系统中测试了一下程序
- 《Effective C++ 改善程序与设计的55个具体做法》——第二章笔记
- pp看书笔记---设计模式之禅第二版 第二章【里氏替换原则】
- Linux程序设计-学习笔记-第二章shell程序设计
- 漂泊者乐园程序系统集成性能测试用例设计#UT001
- 通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统
- 通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统?
- VC编写系统服务程序笔记
- Android 驱动之旅: 第二章 -- 在Android 系统中增加C 可执行程序来访问硬件驱动程序
- VC编写系统服务程序笔记
- 通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统
- ARM系统设计笔记4--调试技巧
- USB视频采集系统 视频测试软件将正式发布(方便调试测试各自摄像头,RAW,RGB,YUV)
- 利用联合体union编写测试系统大小端程序
- 通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统?
- 通过学习学生信息管理系统软件,C程序中,如何设计和编写一个应用系统?
- 如何构建一个ERP系统(需求分析、系统架构、系统设计、系统编码、测试、交付程序及文文件)。