第3章
使用虛擬串列阜VCP
3.1 虛擬串列阜VCP簡介
SIOC與電腦溝通的介面有兩種,一是UART傳輸介面;二是USB傳輸介面。而Virtual COM Port(VCP)就由一個驅動程式,將實體的USB傳輸介面模擬成COM Port傳輸介面,由於並非真正的COM Port,故稱Virtual COM Port。簡單來說,Virtual COM Port就是USB轉RS232的介面。
圖一:USB轉RS232的介面
一般Virtual COM Port的IO有兩組,SIOC也不例外,在SIOC中,一為VCP-to-PC,二為VCP-to-device,示意圖如下:
而Virtual COM Port的兩端,各有專屬的buffer在接收資料,分別為USB_Rx_Buffer與USART_Rx_Buffer,分別處理VCP-to-PC介面與VCP-to-device介面的資料。
3.2 VCP驅動程式安裝和設定
電腦作業系統若是為XP,第一次連接STM Virtual COM Port會無法成功安裝驅動程式,至時可手動到裝置管理員找到STM Virtual COM Port,選擇更新驅動程式,就可指定驅動程式位置(stmcdc.inf)。作業系統若為WIN7,其驅動程式的安裝步驟與XP無異。
電腦與SIOC溝通的軟體,我們以超級終端機與putty為主要介面,期中這裡有些設定是我們需要注意的,以下為超級終端機的設定:
以下是putty的設定,因為某些WIN7的使用者,其系統並沒有超級終端程式,為此我們也介紹putty的設定原則:
做足這些準備,就可以開始與SIOC溝通了!
3.3 電腦與SIOC實驗板的通訊
在描述如何使用scanf()和printf()之前,我們先了解SIOC它底下的IO運作方式,再依序將讀者帶入使用scanf()和printf(),方能更加了解SIOC溝通方式。
l 存取陣列資料
首先是VirtualCOMPort to PC的運作:
在範例程式當中,點選hw_config.c檔找到以下程式碼:
void VCP_To_USB(uint8_t * buffer, int length)
{
int cnt;
for(cnt=0;cnt<length;cnt++){
if (linecoding.datatype == 7){ /* datatype為7bits的資料格式*/
USART_Rx_Buffer[USART_Rx_ptr_in] = buffer[cnt]& 0x7F;
}
else if (linecoding.datatype == 8) { /* datatype為8bits的資料格式*/
USART_Rx_Buffer[USART_Rx_ptr_in] = buffer[cnt];
}
USART_Rx_ptr_in++;
/* To avoid buffer overflow */
if(USART_Rx_ptr_in == USART_RX_DATA_SIZE){
USART_Rx_ptr_in = 0;
}
}
}
USART_Rx_Buffer為一個專屬處理VCP_To_USB方向的資料流的BUFFER,將我們要顯示在超級終端機上的資訊,放入USART_Rx_Buffer中,Virtual COM Port會自動的將資料轉送到PC上。故此,我們只須在main.c中呼叫VCP_To_USB()函式即可。範例如下:
uint8_t Buffer [50]={1,2,3,4,5};
length = strlen(buffer); /*擷取字串長度*/
VCP_To_USB(buffer, length);
接下來我們介紹PC to VirtualCOMPort的運作:
在範例程式當中,點選usb_endp.c檔找到以下程式碼:
void EP3_OUT_Callback(void)
{
uint16_t USB_Rx_Cnt;
/* Get the received data buffer and update the counter */
USB_Rx_Cnt = USB_SIL_Read(EP3_OUT, USB_Rx_Buffer);
/* USB data will be immediately processed, this allow next USB traffic beeing
NAKed till the end of the USART Xfet */
USB_To_USART_Send_Data(USB_Rx_Buffer, USB_Rx_Cnt);
}
此段程式碼負責處理來自PC端超級終端機的訊息,程式將data放入USB_Rx_Buffer,並用USB_Rx_Cnt計算資料筆數。故在main.c當中,我們可以用直接讀取USB_Rx_Buffer的方式收取資料。範例如下:
uint8_t data_buffer [80];
uint8_t index = 0;
while(1){
while(USB_Rx_Cnt==0){} /*USB_Rx_Buffer 為空*/
for(CHAR_Rx_Cnt; CHAR_Rx_Cnt<USB_Rx_Cnt; CHAR_Rx_Cnt++, index++){
buffer[index] = USB_Rx_Buffer[CHAR_Rx_Cnt];
}
USB_Rx_Cnt = 0;
}
index = 0;
l 使用scanf()和printf()
我們用浯陽科技開發的library,將標準函式庫stdio.h裡的printf()與scanf()導向Virtual COM Port的方式實現I/O控制。
l 立即演練
實驗1 “Hello SIOC!”
實驗說明:請用printf()在超級終端機持續印出”Hello, SIOC”,並且使用Delay()函式製造間隔時間。
SIOC…
實驗2 使用超級終端機的SIOC輸入輸出
實驗說明:設計一個簡易程式讓使用者輸入兩個數值,然後輸出運算結果。
|
Type |
Qualifying Input |
Type of argument |
c |
Single character |
char * |
d |
Decimal integer |
int * |
e,E,f,g,G |
Floating point |
float * |
o |
Octal integer |
int * |
s |
String of characters. |
char * |
u |
Unsigned decimal integer. |
unsigned int * |
x,X |
Hexadecimal integer. |
int * |
當程式燒錄進SIOC連接Virtual COM Port後,程式第一行Printf()內的字串是否沒有顯示出來?這是為什麼?又要如何解決呢?
這是因為當使用這燒完程式,離開DFU模式後,SIOC就立刻轉換成Virtual COM Port,此時程式就已經開始執行,但是使用者卻尚未將SIOC與超級終端機或putty連接上,以至於沒有收到程式第一行Printf()的字串內容。
解決方法就是使用getchar()函式,getchar()可讓程式強迫等待來自鍵盤上的字元輸入,藉此方法可讓程式等待在getchar(),不至於在連接超級終端機或putty前,程式就已先偷跑在前,讓使用者漏掉訊息。示意如下:
#include "stdio.h "
int main(void)
{
char a[80];
getchar(); /*強迫程式等待任意字元輸入*/
printf("enter number.");
scanf("%s",&a);
printf("%s \n",a);
}
這是在程式撰寫上的一個小技巧,另外還有使用scanf來讀字串,字串中不能有空白,若有空白會被當成兩個不同的字串,請特別注意這個小細節。
實驗3 計算BMI
實驗說明:在超級終端機可以輸入姓名、身高、體重,並顯示計算姓名與診斷結果。BMI公式:BMI = 體重(kg) / 身高(m) 2
成人的體重分級與標準 |
成人的體重分級與標準 |
|
分 級 |
身體質量指數 |
分 級 |
體重過輕 |
BMI < 18.5 |
體重過輕 |
正常範圍 |
18.5 ≦ BMI <24 |
正常範圍 |
過 重 |
24 ≦ BMI |
過 重 |
l 綜合實驗
設計一個程式,要求使用者輸入身分證字號,並驗證該身分證字號是否正確。這裡我們以A123456789為例子。
此實驗的第一個步驟:先把身分證字號格式化,示意如下:
A |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
|
X1 |
X2 |
D1 |
D2 |
D3 |
D4 |
D5 |
D6 |
D7 |
D8 |
D9 |
接著看下列表格:
A |
B |
C |
D |
E |
F |
G |
H |
J |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
K |
L |
M |
N |
P |
Q |
R |
S |
T |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
U |
V |
X |
Y |
W |
Z |
I |
O |
|
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
|
將第一個英文字母,依據上面表格,拆成兩個數字,分別填到X1與 X2中。
1 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
X1 |
X2 |
D1 |
D2 |
D3 |
D4 |
D5 |
D6 |
D7 |
D8 |
D9 |
利用公式將數字加總:Y=X1 + X2*9 + D1*8 + D2*7 + D3*6 + D4*5 + D5*4 + D6*3 + D7*2 + D8*1 + D9*1。
Y若能夠被10整除,則為正確之身份証號碼。
另外還有性別辨識碼,字串長度等都可以列入辨別身分證字號是否合法的判斷條件,在程式設計當中可以將條件加入進去。
留言列表