|
在為客戶提供單片機(jī)系統(tǒng)、控制器、工控PLC自動(dòng)化傳感系統(tǒng)、電路板、電子產(chǎn)品、儀器儀表、裝置設(shè)備、軟件EXE、安卓APP編程等開發(fā)設(shè)計(jì)定制服務(wù)的時(shí)候(業(yè)務(wù)QQ 2531263726),我會(huì)經(jīng)常分享一些開發(fā)過程中的技術(shù)總結(jié)和難點(diǎn)、基礎(chǔ)知識(shí)和學(xué)習(xí)筆記發(fā)布在微信公眾號(hào)(永珂在線)與大家共享,一直以來我都力求把文章寫得更有故事性、更有吸引力,更簡(jiǎn)單易懂,這是因?yàn)榭粗渌糠肿髡吆屠蠋煂懙慕坛毯图夹g(shù)文檔很枯燥就很惱火,雖然他們功力深厚但是出拳無味,我就想改變。我想,技術(shù)文檔打破傳統(tǒng)寫法,是可以寫得跟小說一樣引人入勝有吸引力的,我的文筆會(huì)比較輕快明麗、淺顯易懂,甚至扯淡。以前的幾篇文章寫得比較爛,我也不去修改了,此文開始:通俗易懂、引人入勝、循序漸進(jìn)。當(dāng)然,我也不是專業(yè)作家,不能一蹴而就,只寄望于一次比一次更好。廢話就說到這里,故事開始,進(jìn)入正題:
1. 背景介紹
幾個(gè)月前,一位尊敬的客戶R加我的QQ(業(yè)務(wù)QQ 2531263726)好友:
“你好,我們有個(gè)控制器的項(xiàng)目需要幫助,請(qǐng)問能來談?wù)剢幔俊?/font>
“好,可以,請(qǐng)問地址在哪里?”
“成都市某某縣某某路某某號(hào),電話18然后嘰里呱啦。”
“嗯,好的,我安排一下時(shí)間過來。”
于是我就和客戶簡(jiǎn)單電話溝通了一下任務(wù)需求,就是要做什么東西有什么要求,然后約好了時(shí)間面談。本案是為了一款新研制的清洗設(shè)備開發(fā)一個(gè)控制器,從最初到現(xiàn)在幾次改進(jìn)設(shè)計(jì)最終選定此款串口觸摸屏作為顯示器件。
最初的設(shè)計(jì)方案出于成本和其他因素的考慮是利用OLED和LCD作為設(shè)備的顯示器,顯示設(shè)備的運(yùn)行狀態(tài)、流量、溫度和壓力參數(shù)。這兩種顯示器價(jià)格便宜,但是功能較為單一、美觀性稍微差一點(diǎn),后來有一天,客戶甩了一個(gè)東西給我,是一個(gè)4.5寸的串口觸摸屏和一本巴掌那么大小的寥寥幾頁的說明手冊(cè)給我,要把所有的顯示和按鍵功能集成到這個(gè)觸屏上面。簡(jiǎn)單了解一下,這個(gè)屏雖然以前沒有使用過,但是串口通信和控制我這里熟悉得很,我想只要廠家能把產(chǎn)品生產(chǎn)出來并且有說明書,我這里就能二次開發(fā)出滿足要求的功能。
根據(jù)說明手冊(cè)里面提供的信息,去下載了詳細(xì)的使用說明書、配套軟件和參考例程,粗略一看,使用起來似乎不難,但是真正在后面開發(fā)的時(shí)候卻又是一波三折。
2. 串口觸摸屏的介紹和開發(fā)說明
這款串口觸摸屏的尺寸是4.5寸,在橫向(寬邊)有853個(gè)點(diǎn)像素,縱向(窄邊)479個(gè)點(diǎn)像素,在使用的時(shí)候不超出這個(gè)尺寸參數(shù)都是能夠在屏幕上顯示。
1.JPG (43.99 KB, 下載次數(shù): 65)
下載附件
2018-8-18 22:03 上傳
這個(gè)觸摸屏完全可以采用串口通信進(jìn)行操作,包括參數(shù)顯示、觸摸按鍵控制等,串口通信協(xié)議按照?qǐng)D 2設(shè)置即可,很簡(jiǎn)單的幾個(gè)參數(shù)設(shè)置,波特率、數(shù)據(jù)位、校驗(yàn)位、停止位。
2.JPG (37.2 KB, 下載次數(shù): 63)
下載附件
2018-8-18 22:04 上傳
在開發(fā)中只需要接4根線就可以運(yùn)行觸摸屏,包括:
VCC引腳:自然是接5V或者3.3V的直流電源正極;
GND引腳:接直流電源的負(fù)極;
TX引腳: 如果是由單片機(jī)控制觸摸屏的顯示,就接單片機(jī)串口的RX引腳;
RX引腳: 如果是由單片機(jī)控制觸摸屏的顯示,就接單片機(jī)串口的TX引腳;
3.JPG (15.45 KB, 下載次數(shù): 70)
下載附件
2018-8-18 22:05 上傳
2.1 串口觸摸屏的程序開發(fā)說明
實(shí)際上此款觸摸屏的顯示和控制只需要單片機(jī)的串口發(fā)送或者接收一些特定的字符串指令即可。
例如,我們想對(duì)觸摸屏清屏,只需要利用單片機(jī)串口向觸摸屏發(fā)送字符串"CLS(0);\r\n"即可,其中的”CLS(0);”是清屏指令,用0號(hào)顏色黑色清除屏幕,\r\n表示讓觸摸屏立刻執(zhí)行這一指令。
4.JPG (14.55 KB, 下載次數(shù): 63)
下載附件
2018-8-18 22:05 上傳
以上就類似于單片機(jī)向觸摸屏打了一個(gè)招呼,交代一些事情:
“嗨!觸摸屏兄弟,把你的屏幕用黑色作為背景清除一下。”
那么一般來說,觸摸屏收到指令執(zhí)行完成后還需要向單片機(jī)反饋一個(gè)消息,發(fā)送字符串“OK”給單片機(jī),就像在說“OK,弄好了!”
這個(gè)“OK”字符串只有觸屏接收到“\r\n”字符串指令,并且執(zhí)行完成后才會(huì)向單片機(jī)反饋。不過大家做事也不能著急,在單片機(jī)在向觸屏發(fā)送指令確認(rèn)執(zhí)行后,需要延時(shí)200-300毫秒,等觸屏兄弟休息一下,收到觸屏的“OK”的回話后再接著干活。
又如,我們想要在屏幕上某個(gè)位置開始顯示12點(diǎn)的漢字“永珂在線”,就只需要利用單片機(jī)串口向觸摸屏發(fā)送字符串"DS12(0, 0,'永珂在線',1); \r\n ",就能在觸摸屏的(0,0)位置開始顯示字符串“永珂在線”四個(gè)漢字,其中的1表示字體的顏色白色。同樣地,觸屏執(zhí)行完成后,也會(huì)向單片機(jī)反饋“OK”。當(dāng)然,也不是每個(gè)指令語句后面都要加“\r\n”,多發(fā)送幾條指令后再加“\r\n”,將是更好的編程選擇。
5.JPG (20.57 KB, 下載次數(shù): 51)
下載附件
2018-8-18 22:05 上傳
這款串口屏的使用就是類似這樣的,我只是舉例兩個(gè)例子,更多的背景設(shè)置、觸摸按鍵配置等等功能,在你購買這塊觸摸屏的時(shí)候,在商家給你的說明書里有詳細(xì)介紹。
2.2 在單片機(jī)里面寫程序
觸摸屏了解了,線接好了,接下來的工作就是編寫單片機(jī)的程序。
(1)這里我首先介紹的是一款以51為核心的單片機(jī)(STC15F2K60S2)的與觸屏通信操作的編程方法。
第一步,既然是串口觸摸屏,首先自然是配置單片機(jī)的串口,直接一點(diǎn),上代碼吧。
void UartInit(void) //115200bps@11.0592MHz 串口1初始化
{
SCON = 0x50; //8位數(shù)據(jù),可變波特率
AUXR &= 0xBF; //定時(shí)器1時(shí)鐘為Fosc/12,即12T
AUXR &= 0xFE; //串口1選擇定時(shí)器1為波特率發(fā)生器
TMOD &= 0x0F; //設(shè)定定時(shí)器1為16位自動(dòng)重裝方式
TL1 = 0xFE; //設(shè)定定時(shí)初值
TH1 = 0xFF; //設(shè)定定時(shí)初值
ET1 = 0; //禁止定時(shí)器1中斷
TR1 = 1; //啟動(dòng)定時(shí)器1
ES=1; //使能串口中斷
EA=1; //打開總中斷
}
以上UartInit程序段,就將單片機(jī)的串口1配置為波特率為115200bps,8位數(shù)據(jù)的通信參數(shù)。
第二步,編寫串口發(fā)送的程序段,串口發(fā)送的程序段分為兩部分,第一個(gè)是串口發(fā)送一個(gè)字符,另一個(gè)是串口發(fā)送字符串。
void SendData(unsigned char dat) //(1)發(fā)送一個(gè)字節(jié)(一個(gè)字符)
{ unsigned char i=0;
ACC=dat;
SBUF=dat;
do
{ _nop_();
i++;
}while(!TI && i<200);
TI=0;
}
在這里為了防止串口發(fā)送進(jìn)入死循環(huán),我將官方參考例程做了一下小修改,增加了一個(gè)計(jì)數(shù)變量i,當(dāng)執(zhí)行了200個(gè)指令周期的延時(shí)后假如串口還沒有發(fā)送完一個(gè)字符,就強(qiáng)制退出這個(gè)串口字符發(fā)送程序。
void SendString(unsigned char *s) //(2)發(fā)送字符串
{
unsigned char i=0;
while(*s)
{
SendData(*s++);
i++;
if(i>=250) break;//防止進(jìn)入死循環(huán),一次最多250個(gè)字符
}
Delay1ms(10);
}
在這里也將官方參考例程做了一下小修改,同樣為了避免進(jìn)入死循環(huán),增加了一個(gè)計(jì)數(shù)變量i,一個(gè)字符串最大只能有250個(gè)字符,超過這個(gè)數(shù)量則退出字符串發(fā)送程序。
接下來的操作就是比較簡(jiǎn)單的,在程序的任意位置調(diào)用SendString子函數(shù)就能進(jìn)行觸摸屏的操作,例如調(diào)用SendString("DS24(510,410,'中',1);"); 就能在屏幕的(510,410)位置顯示一個(gè)白色的24點(diǎn)陣漢字“中”。
第三步,前面說了單片機(jī)向觸屏發(fā)送數(shù)據(jù)和指令,自然單片機(jī)還需要接收觸屏返回的反饋信號(hào)、按鍵標(biāo)號(hào)等信息,這里我采用串口中斷來接收來自觸屏的反饋數(shù)據(jù)。
unsigned char xdata received_data[4]; //串口接收到的按鍵編號(hào)數(shù)據(jù)
unsigned char xdata feedback_data[2];//串口屏執(zhí)行指令后的反饋數(shù)據(jù)
void Usart() interrupt 4 //串口1的中斷
{
unsigned char received_temp;
if(RI) //假如有數(shù)據(jù)接收事件,接收到數(shù)據(jù)
{RI=0;
received_temp=SBUF; //串口接收到的數(shù)據(jù)
received_data[0]=received_data[1];
received_data[1]=received_data[2];
received_data[2]=received_data[3];
received_data[3]=received_temp;
if(received_data[0]=='B' && received_data[1]=='N' && received_data[2]==':' && received_data[3]!='0' ) //觸摸按鍵返回的指令格式是BN:X
{command_received=1;
command_data=received_data[3]; //返回BN:X指令中的X代碼
}
feedback_data[0]=feedback_data[1];
feedback_data[1]=received_temp;
if (feedback_data[0]=='O' && feedback_data[1]=='K')
{feedback_ok=1;
}
}
if(TI)
{TI=0;
}
}
這里我定義了2個(gè)數(shù)據(jù)緩沖區(qū),received_data是觸屏按鍵編號(hào)緩沖,當(dāng)你用手指在觸屏上點(diǎn)擊不同的按鍵區(qū)域的時(shí)候,觸屏?xí)鶕?jù)預(yù)先的配置返回BN:1,BN:2,BN:3等等字符串,其中的數(shù)字1,2,3就表示你手指點(diǎn)擊的屏幕上哪個(gè)編號(hào)的區(qū)域,BN:1表示手指點(diǎn)擊了1號(hào)區(qū)域,BN:2表示手指點(diǎn)擊了2號(hào)區(qū)域,以此類推。
feedback_data是單片機(jī)向觸摸屏發(fā)送指令后,觸屏接收到并執(zhí)行后向單片機(jī)返回的“OK”信息,當(dāng)單片機(jī)收到“OK”就表示觸屏把上一條指令執(zhí)行完成了。
(2)以上是51單片機(jī)的,下面講一講STM32單片機(jī)的部分參考程序,本段程序來自于該款觸屏的說明書。
第一步,自然是串口初始化。
void USART1_Init(void)
{
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE );
USART_ClockInitStructure.USART_Clock = USART_Clock_Disable; // 時(shí)鐘低電平活勱
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low; // 時(shí)鐘低電平
USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge; // 時(shí)鐘第二個(gè)邊沿迕行數(shù)據(jù)捕獲
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable; // 最后一位數(shù)據(jù)癿時(shí)鐘脈沖丌從SCLK輸出
/* Configure the USART1 synchronous paramters */
USART_ClockInit(USART1, &USART_ClockInitStructure); // 時(shí)鐘參數(shù)刜始化謳置
USART_InitStructure.USART_BaudRate = 115200; // 波特率為:115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 8 位數(shù)據(jù)
USART_InitStructure.USART_StopBits = USART_StopBits_1; // 在幀結(jié)尾傳輸 1 個(gè)停止位
USART_InitStructure.USART_Parity = USART_Parity_No ; // 奇偶失能
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 硬件流控刢失能
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 収送使能+接收使能
/* Configure USART1 basic and asynchronous paramters */
USART_Init(USART1, &USART_InitStructure);
/* Enable USART1 */
USART_ClearFlag(USART1, USART_IT_RXNE); //清中斷,以免一啟用中斷后立即產(chǎn)生中斷
USART_ITConfig(USART1,USART_IT_RXNE, ENABLE); //使能 USART1 中斷源
USART_ITConfig(USART1, USART_IT_TC, ENABLE);
USART_Cmd(USART1, ENABLE); //USART1 總開關(guān):開啟
}
第二步,串口發(fā)送字符串的子程序。
void GpuSend(char * buf1)
{ u8 i=0;
while (1)
{ if (buf1[ i]!=0)[ i]
{ USART_SendData(USART1, buf1[ i]); //収送一個(gè) byte 刡串口[ i]
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}; //等待収送結(jié)束
i++;
}
else return;
}
}
第三步,在任意程序里調(diào)用串口發(fā)送指令去命令觸屏工作。
GpuSend("CLS(13);BOX(0,0,219,175,15);BOX(1,1,218,174,0);BOXF(2,2,217,17,3);PL(2,
18,218,18,0);\r\n");
這里的STM32的程序只是部分程序段,在使用的過程中還有時(shí)鐘配置、引腳配置等其他程序,這里不一一贅述了。
3. 你需要注意的事
該怎么調(diào)試
有時(shí)候作為開發(fā)者我們的設(shè)想是很好的,以為一次就可以寫出天衣無縫的代碼,然而現(xiàn)實(shí)是比較殘酷的,有時(shí)候以為是嚴(yán)格按照規(guī)則和使用說明來寫的程序,但是稀里糊涂地就會(huì)出現(xiàn)這樣或者那樣的問題,這時(shí)候就需要調(diào)試了。
磨刀不誤砍柴工,既然是串口通信,那串口助手就是少不了的,如圖 2的Commix軟件就是不錯(cuò)的選擇。將串口數(shù)據(jù)線(TTL電平的)或者USB轉(zhuǎn)串口TTL數(shù)據(jù)線插到電腦上,將數(shù)據(jù)線的TX接單片機(jī)的RX,數(shù)據(jù)線的RX接單片機(jī)的TX,然后數(shù)據(jù)線的地線和單片機(jī)共地即可。在串口助手界面你能看到單片機(jī)發(fā)送出來的數(shù)據(jù),你也可以模擬觸屏向單片機(jī)發(fā)送反饋數(shù)據(jù)。
以上的方式是用串口助手替代觸屏與單片機(jī)通信,有一定作用但是不能完全反映單片機(jī)與觸屏的工作情況,因?yàn)榇藭r(shí)數(shù)據(jù)鏈路是沒有和觸屏連接的,我們要完全監(jiān)視單片機(jī)與觸屏的工作狀態(tài),就需要對(duì)連接線路進(jìn)行簡(jiǎn)單搭建。
6.JPG (20.55 KB, 下載次數(shù): 66)
下載附件
2018-8-18 22:06 上傳
如圖 6,這樣的接線方式,就能利用電腦上的串口助手完全監(jiān)視單片機(jī)與觸屏之間的通信了,不管是單片機(jī)串口與觸屏通信的發(fā)送還是接收過程數(shù)據(jù),都能顯示在串口助手的界面。
要確定字符串是否結(jié)束
可以在2.2中知道,在串口發(fā)送的時(shí)候是以最后一個(gè)字符是不是0來作為結(jié)束標(biāo)志的。曾經(jīng)我有過這樣的經(jīng)歷,定義了一個(gè)數(shù)組A[5],分別給第0-4為元素賦值,例如我要顯示單詞“stand”,就令A(yù)[0]=’s’; A[1]=’t’; A[2]=’a’; A[3]=’n’; A[4]=’d’;我曾經(jīng)天真地以為再調(diào)用SendString(A)這樣子就可以了,可是,這樣子做的結(jié)果就是屏幕老是進(jìn)入初始化狀態(tài),當(dāng)時(shí)不明原因,后來通過串口助手調(diào)試發(fā)現(xiàn),在字符串“stand”后面老是多了一個(gè)異常字符,后來,我就重新定義了一下數(shù)組為A[6],并令最后一位元素A[5]=0,如此之后觸屏恢復(fù)正常顯示。出現(xiàn)這個(gè)問題的原因就是由于之前字符串沒有結(jié)束標(biāo)志,導(dǎo)致串口在A發(fā)送完后隨機(jī)發(fā)送了幾個(gè)數(shù)據(jù)給觸屏,導(dǎo)致混亂。
不要輕易使用while循環(huán)
在之前的程序設(shè)計(jì)中,我會(huì)使用while來等待ADC轉(zhuǎn)換完成,等溫度采集完成,等待串口發(fā)送完成。可以后來發(fā)現(xiàn)觸屏經(jīng)常死屏,最初懷疑觸屏有問題,可是廠家堅(jiān)持說沒有出現(xiàn)這樣的狀況,那我就自己先查查程序了,初步是懷疑while的過度使用,所以把所有的while循環(huán)都加上限制,例如假如ADC轉(zhuǎn)換等待多少時(shí)間后還沒有轉(zhuǎn)換完成則跳出循環(huán),假如串口發(fā)送多少個(gè)字符后還沒有完成發(fā)送那也跳出循環(huán)。當(dāng)把所有的while都加上跳出的限制后,一切就變得正常了。
好了,這篇文章就介紹到這里,本文花了我?guī)滋斓挠锌諘r(shí)間,也是寫得字?jǐn)?shù)最多的一篇文章。謝謝查看,希望有幫助。
公眾號(hào)二維碼 - 小.jpg (24.99 KB, 下載次數(shù): 54)
下載附件
2018-8-18 22:06 上傳
微信隨意打賞-小.png (35.62 KB, 下載次數(shù): 57)
下載附件
2018-8-18 22:06 上傳
四川成都控制器電路板儀器儀表開發(fā)定制可以找我
|
評(píng)分
-
查看全部評(píng)分
|