这次的目标是要实现用 USB 口来控制七段数码管。
硬件上面选用《圈圈教你玩USB》配套的实验板。上面的单片机为STC89S52。实验板上P0接口用来和D12通讯,P1接口连接到一组开关按钮上,P2接口上有一组LED,LED另外一端通过10K电阻上拉。下面用色块对这些端口的用途做了简单标记:
最开始的设想是数码管(用的还是上次出场过的那一款数码管,共阳极,【参考1】)阳极连接到P1(可以理解为SEG选择 Pin接正极),阴极连接到P2(数码段 Pin接负极)。实验发现数码管根本不亮,检查很多次后尝试去掉六个数码段的连接终于能够点亮一段数字。这才恍然大悟,因为共阳极上还有板载的LED所以会使得电压很奇怪,不足以推动全部。同时显示,所以需要更改方案。
做到这里,我忽然明白极客工坊大神弘毅提到的:“驱动数码管限流电阻肯定是必不可少的,限流电阻有两种接法,一种是在d1-d4阳极接,总共接4颗。这种接法好处是需求电阻比较少,但是会产生每一位上显示不同数字亮度会不一样,1最亮,8最暗。另外一种接法就是在其他8个引脚上接,这种接法亮度显示均匀,但是用电阻较多。” 因为电压相同,数字1只需要点亮两根LED,8需要点亮七根。
修改之后,阳极连接到P2,阴极连接到P1上。实验发现即使4个数字同时显示仍然是可以清晰辨认的。连接如下图所示:
继续尝试在上位机程序中自动扫描点亮每个LED,前面一篇Arduino就是使用类似的方法点亮的。实做之后发现这样做会导致每个数码管亮灭之间的间隔太长,这样在人类看起来是逐个亮灭的而不是同时亮。猜测这是程序本身发送和USB传输Delay太长导致的。初步估计每个数字显示间隔至少在200ms以上。如果想做一个类似跑马灯的程序用这样的方案没问题,但是如果想持续稳定的显示数字这个方案不可行。
最后上位机程序直接发送显示的数值,由Firmware本身解析,同时利用单片机上的定时器(15ms一次),不断刷新每个显示位。开始时,Firmware中定时器产生中断后,ISR中将四位数值轮流显示一次,但是实验结果肉眼只能看到最后一个点亮的数值。估计这个可能是因为ISR中每个数码位显示过快,而他们点亮的时间远远小于不在ISR中的时间。
经过无数次的调试后,终于完成了。
拍了一个视频,PC来控制七段数码管
http://www.tudou.com/programs/view/-D_w29Pwavc/?resourceId=414535982_06_02_99
对应的Firmware关键点在于中断服务函数
void Timer0Isr(void) interrupt 1 { //LabzDebug_Start static i=0; //LabzDebug_End //定时器0重装,定时间隔为5ms,加15是为了修正重装所花费时间 //这个值可以通过软件仿真来确定,在这里设置断点,调整使两次运行 //时间差刚好为5ms即可。 TH0=(65536-Fclk/1000/12*5+15)/256; TL0=(65536-Fclk/1000/12*5+15)%256; // //LabZDebug_Start P2=1 << i; P1=zBuf[i]; i++; if (i==4) {i=0;} //LabZDebug_End }
Firmware下载 HID7Seg
PC端上位机主要代码
int n=0; while (kbhit()==0) { WriteReportBuffer[1]=Seven_Dig[n / 1000 % 10]; WriteReportBuffer[2]=Seven_Dig[n / 100 % 10]; WriteReportBuffer[3]=Seven_Dig[n / 10 % 10]; WriteReportBuffer[4]=Seven_Dig[n %10]; printf("%d \n",n); //调用WriteFile函数发送数据 Result=WriteFile(hUsb, WriteReportBuffer, 9, &lpNumberOfBytesWritten, NULL); //如果函数返回失败,则可能是真的失败,也可能是IO挂起 if(Result==FALSE) { //获取最后错误代码 LastError=GetLastError(); //看是否是真的IO挂 if((LastError==ERROR_IO_PENDING)||(LastError==ERROR_SUCCESS)) { return TRUE; } //否则,是函数调用时发生错误,显示错误代码 else { printf("Sending error:%d \n",LastError); //如果最后错误为1,说明该设备不支持该函数。 if(LastError==1) {printf("This device doesn't support WriteFile function \n");} } } n=(n++)%10000; }//while (kbhit()==0)
完整的代码下载 USB7Seg
参考:
1. http://www.lab-z.com/4digitial/ Arduino 四位数码管实验
2. http://www.geek-workshop.com/forum.php?mod=viewthread&tid=82&highlight=%CA%FD%C2%EB%B9%DC arduino学习笔记13 - 4位数码管实验