本文适合经常通过MCU控制外围器件(如显示,通讯等)底层开发的朋友,本人调试的硬件不多,但是善于从痛苦的经历总结经验。呵呵,如果发现本文有什么问题,可以跟联系,Email:ochapman@qq.com
相信有很多编写程序调试硬件的朋友都有这样的经历。
1、无法确定出现的问题是来自硬件还是程序。
2、出现的问题很多,多到你都不知道从哪下手。
3、没有什么问题,呵呵,那是什么反应都没有。
4、大概有个反应了,但是飘忽不定,没有稳定性可言。
为了方便说明,以ARM(LPC2103)控制液晶显示屏12864显示为例子,
在编程调试前,需要哪些步骤?
1、了解硬件电气特性,满足硬件工作的条件,确定引脚连接正确,工作电压正确。这方面,认真研究一下器件的datasheet是很有必要的,很多人经常喜欢“拿来主义”--抄网上的电路图,这虽然是一个捷径,但是对一个有志于该行业的人,这种行为应该少做,因为现在你面对的是一个有网上电路图的器件,如果有一天,让你去接触一个全新的器件,网上没有电路图,你该怎么办?还有,网上的电路也不能保证100%的正确,也许是根据他的系统特点剪裁的,并不适合我们的系统。但是,又不能死守着datasheet,因为datasheet也有可能是错误的,尤其是小公司的,datasheet自己又没有,随便下载一个传给你,这被称为技术支持,呵呵。像是HS12864购于广州新赛格电子,3.3V的工作电压,V0(第3脚,)手册(厂家提供的,各个厂家不同12864的电路也许不一样,也是我索取手册的原因)上表明悬空(第18脚vout也是)。但实际上,需要在V0脚上接5V的电压(3.3V都不行)。
2、了解硬件的通讯接口(或者说“控制接口”更合适一点),一个器件要被MCU控制,当然要有自己的接口了,比如uart,spi,usb等,如果你对这些接口很熟悉的话,编起程序也比较省力。如果不熟悉,最好看MCU接口的资料。这里有一个测试思路:
(1)要满足MCU控制器件,必须满足:MCU可以正确发送指令和读取数据,首先要测试的是,MCU要正确发送控制指令,要保证MCU控制线到器件的指令是无误的。可以依靠示波器或者仿真器来验证发送的正确。
(2)器件可以正确读取MCU发送的指令,这点,时序匹配应该是最需要关注的。因为有时候我们也会看到,MCU发送的指令明明正确,但是器件就像挂了的感觉,无反应。或者器件就是就像得了神经病,不正常。一般情况下MCU的速度往往快于器件的速度,那么就要保证器件有足够的时间去接受MCU发送的指令。比如HS12864-12的速度小于LPC2103, 那么就这样的可能,LPC2103发送给12864指令,后者还没有足够时间去读取指令,就被LPC2103的下一个控制信号给制止了,如下程序(注明:该程序尚未优化,也没有必要优化,并行,实际很少用吧,呵呵):
/*********************************************************************************************************
**Function: void LcdWriteCommand(uint8 command)
**Input:
**Output:
**Description: Parallel mode 8 bit interface.Mcu to LCD
*********************************************************************************************************/
void LcdWriteCommand(uint8 command)
void LcdWriteCommand(uint8 command)
{
LcdCheckBusy();//Check busy
IO0CLR=E;//Enable signal
IO0CLR=DI;//Set to instruction mode.
IO0CLR=RW;//Set to write mode.
IO0SET=command;//Write command.
IO0CLR=~command&0x000000FF;//Write command.
Delaynus(20);
IO0SET=E;//Eable signal
IO0CLR=E;//Disable signal
Delaynms(2);//This is important!
IO0SET=DI;//Set to data mode?
IO0SET=RW;//Set to read mode?
}
该函数的如果没有该语句:
Delaynms(2);//This is important!
会怎么样?会导致12864接受的指令不正常,12864是在下降沿读取数据,如果IO0CLR=E,就直接IO0SET=DI(如果该函数没有该语句,那么其他函数也会有的,为了IO0CLR=E,之后让12864有足够的时间去读,Delaynms是必须的,IO0SE=DI和IO0SET=RW则不一定,尚未优化),会使12864来不及读取。不同的频率的MCU此处应该是不同。
3、有了上面两方面的准备,写初始化程序:
(1)MCU接口初始化的程序,比如“void LcdBusPort(void)”,让MCU的io口满足数据传输的配置。程序如下:
/*********************************************************************************************************
**Function: void LcdPortInit(void)
**Input:
**Output:
**Description: Init the port to lcd
*********************************************************************************************************/
void LcdPortInit(void)
{
PINSEL0&=0xFF000000;//Set as GPIO,p0.0~p0.11
IO0DIR|=0x00000FFF;//Set all port as output, except for read BF
}
(2)器件的初始化程序void LcdInit(void),初始化的目的就是器件满足工作的状态,
/*********************************************************************************************************
**Function: void LcdInit(void)
**Input:
**Output:
**Description: Init the lcd, paralled mode, 8 bit interface.
*********************************************************************************************************/
void LcdInit(void)
{
//IO0CLR=RST;
//Delaynms(100);
IO0SET=RST;//Reset the LCD
Delaynms(100);//Wait time>40ms.
LcdWriteCommand(0x30);//Function set:001+DL(1:8 bit interface)+X+RE(0,basic instruction)+X+X
Delaynms(10);//Wait time>100us
LcdWriteCommand(0x03);//HOME: set DDRAM address counter(AC) to "00H", and put cursor to orgin,
//the content of DDRAM are not changed
Delaynms(10);//Wait time>37us
LcdWriteCommand(0x0C);//Display ON/OFF control:
Delaynms(40);//Wait time>10ms
LcdWriteCommand(0x06);//Entry mode set
Delaynms(40);
LcdWriteCommand(CLEAR);
Delaynms(40);
}
4、写完初始之后,干什么?让器件马上进行工作?进行数据处理?不是。在12864里也一样,如果我想马上就想显示“Hello, oChapman”那我就要花费更多的时间去发现问题,最后还是要走这一步的。 现在要做的是测试写指令,注意,不是数据,虽然已经在LcdInit()上存在写指令,但现在要测试的是指令这个函数能否正确的工作呢?这时需要一个最小测试法(我个人捏造的词,呵呵),不涉及数据处理,如果添加数据处理,就会增添这样的问题,到底是写指令的不正常,还是数据处理的错误?这个最小测试法可以让你验证你的器件是已经工作了从而避免其他问题的干扰。对于12864的写指令验证,可以是如下程序:
The simplest test for Lcd12864<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
while(1)//A simple test for LCD
{
/*Display ON, Cursor ON, Blink ON.*/
LcdWriteCommand(0x<?xml:namespace prefix = st1 ns = "urn:schemas-microsoft-com:office:smarttags" />0F);
Delaynms(3000);
/*Display, Cursor and Blink OFF*/
LcdWriteCommand(0x08);
Delaynms(1500);
}
通过上述语句,我们直接验证器件的是否正常工作(电气特性,部分引脚正确了),呵呵,只要可以工作,接下来的事情就好办多了。
验证了写指令,接下来的写数据等函数可以类似验证了。
5、写好了底层的驱动程序,当然底层验证可以稳定工作才行。接下来编写跟硬件无关的程序了。这就不是本文涉及的了。
用户1589396 2009-2-16 15:05
用户155073 2008-8-2 11:51