您好,登錄后才能下訂單哦!
小編給大家分享一下怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī),相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
一、環(huán)境簡(jiǎn)介
1. 軟硬件環(huán)境
下位機(jī):CC2530 OS:vmware + ubuntu
在這里彭老師采用的是CC2530,讀者也可以采用其他的板子,我們只需要該板子有串口,可以和PC通信,同時(shí)板子上有可設(shè)置的led燈、繼電器以及可以采集數(shù)據(jù)的傳感器即可。
2. 硬件連接圖
硬件連接圖如下:
該款CC2530已經(jīng)集成了CH340芯片,usb線連接電腦,即可被識(shí)別。
3. pc下識(shí)別串口
如果該串口被PC獲取,名字為COMn【n為某整數(shù)】。
windows下串口
4. ubuntu下識(shí)別串口
首先需要vmware抓取串口【串口在同一時(shí)刻要么被windows抓取要么被vmware抓取】,按下圖所示,點(diǎn)擊連接即可:
虛擬機(jī)抓取串口
但是往往ubuntu中沒有ch440的驅(qū)動(dòng),經(jīng)過(guò)實(shí)際測(cè)試,ubuntu14及之前的版本都沒有這個(gè)驅(qū)動(dòng),ubuntu16以上的版本有這個(gè)驅(qū)動(dòng)。
如果沒有ch440驅(qū)動(dòng)可以用以下方法安裝對(duì)應(yīng)的驅(qū)動(dòng):
1 make 2 sudo make load 3 ls /dev/ttyUSB0
ubuntu安裝串口驅(qū)動(dòng)
按照上述步驟,會(huì)生成設(shè)備文件**/dev/ttyUSB0**。
ls /dev/ttyUSB0 -l crw-rw---- 1 root dialout 188, 0 Jan 15 05:45 /dev/ttyUSB0
c : 字符設(shè)備 rw-rw---- :文件操作權(quán)限
188, 0 :主次設(shè)備號(hào)
3、4節(jié)提到的usb轉(zhuǎn)串口驅(qū)動(dòng)和linux下驅(qū)動(dòng)源碼后臺(tái)【GH】回復(fù) ch440 即可獲得
【注意】如果是其他開發(fā)板,自行安裝其他的串口驅(qū)動(dòng)。
二、模塊設(shè)計(jì)
上位機(jī)和下位機(jī)的通信往往都是通過(guò)串口,linux下往往生成字符設(shè)備ttyUSB0【有的是ttyS0】,操作串口設(shè)備就只需要操作該字符設(shè)備即可。
下面我們?cè)O(shè)計(jì)上下位機(jī)的軟件模塊。
1. 信令
設(shè)計(jì)上位機(jī),首先需要設(shè)計(jì)上位機(jī)下發(fā)給下位機(jī)的指令格式,上位機(jī)按照該指令格式發(fā)送命令給下位機(jī),下位需嚴(yán)格按照該指令格式進(jìn)行解析指令。
含義如下:
device:要操作的設(shè)備
data :對(duì)應(yīng)的設(shè)備及其額外的數(shù)據(jù)
CRC :校驗(yàn)碼
# :信令終止符
信令格式可以根據(jù)需要擴(kuò)展或者精簡(jiǎn)。
其中device定義如下【可以根據(jù)實(shí)際情況進(jìn)行擴(kuò)展】:
#define DEV_ID_LED_ON 0X1 #define DEV_ID_LED_OFF 0X2 #define DEV_ID_DELAY 0X3 #define DEV_ID_GAS 0X4
【注意】為便于理解,我們暫不考慮效率問(wèn)題。
2. 上傳數(shù)據(jù)
下位機(jī)需要采集傳感器的數(shù)據(jù)并通過(guò)串口上傳,數(shù)據(jù)結(jié)構(gòu)定義如下:
struct data{ unsigned char device; unsigned char crc; unsigned short data; };
device 設(shè)備
data 采集的數(shù)據(jù)
crc 校驗(yàn)碼
3. 功能模塊
現(xiàn)在就可以開始設(shè)計(jì)軟件的各個(gè)功能模塊了。
下位機(jī)
下位機(jī)流程圖
下位主要任務(wù)就是循環(huán)接收上位機(jī)通過(guò)串口下發(fā)的數(shù)據(jù),然后解析該指令內(nèi)容,操作對(duì)應(yīng)的硬件。
上位機(jī)
上位機(jī)
上位機(jī)主要任務(wù)是打印菜單,由用戶針對(duì)菜單做出選擇,然后按照指令格式封裝命令,并通過(guò)串口將該命令下發(fā)給下位機(jī)。
三、 下位機(jī)功能函數(shù)
cc2530的操作原理,本文不討論,如果是其他開發(fā)板,只需要修改串口操作函數(shù)。
1. LED初始化
/**************************************************************************** * 名 稱: InitLed() * 功 能: 設(shè)置LED燈相應(yīng)的IO口 * 入口參數(shù): 無(wú) * 出口參數(shù): 無(wú) ****************************************************************************/ void InitLed(void) { P1DIR |= 0x01; //P1.0定義為輸出口 LED1 = 0; }
2. 初始化UART
/**************************************************************** * 名 稱: InitUart() * 功 能: 串口初始化函數(shù) * 入口參數(shù): 無(wú) * 出口參數(shù): 無(wú) *****************************************************************/ void InitUart(void) { PERCFG = 0x00; //外設(shè)控制寄存器 USART 0的IO位置:0為P0口位置1 P0SEL = 0x0c; //P0_2,P0_3用作串口(外設(shè)功能) P2DIR &= ~0xC0; //P0優(yōu)先作為UART0 U0CSR |= 0x80; //設(shè)置為UART方式 U0GCR |= 11; U0BAUD |= 216; //波特率設(shè)為115200 UTX0IF = 0; //UART0 TX中斷標(biāo)志初始置位0 U0CSR |= 0x40; //允許接收 IEN0 |= 0x84; //開總中斷允許接收中斷 }
3. 串口發(fā)送函數(shù)
/********************************************************************** * 名 稱: UartSendString() * 功 能: 串口發(fā)送函數(shù) * 入口參數(shù): Data:發(fā)送緩沖區(qū) len:發(fā)送長(zhǎng)度 * 出口參數(shù): 無(wú) ***********************************************************************/ void UartSendString(char *Data, int len) { uint i; for(i=0; i<len; i++) { U0DBUF = *Data++; while(UTX0IF == 0); UTX0IF = 0; } }
4. 串口中斷處理函數(shù)
/********************************************************************** * 名 稱: UART0_ISR(void) 串口中斷處理函數(shù) * 描 述: 當(dāng)串口0產(chǎn)生接收中斷,將收到的數(shù)據(jù)保存在RxBuf中 **********************************************************************/ #pragma vector = URX0_VECTOR __interrupt void UART0_ISR(void) { URX0IF = 0; // 清中斷標(biāo)志 RxBuf = U0DBUF; }
5. 煙霧傳感器數(shù)據(jù)讀取
/**************************************************************** * 名 稱: myApp_ReadGasLevel() * 功 能: 煙霧傳感器數(shù)據(jù)讀取 * 入口參數(shù): 無(wú) * 出口參數(shù): 無(wú) *****************************************************************/ uint16 myApp_ReadGasLevel( void ) { uint16 reading = 0; /* Enable channel */ ADCCFG |= 0x80; /* writing to this register starts the extra conversion */ ADCCON3 = 0x87; /* Wait for the conversion to be done */ while (!(ADCCON1 & 0x80)); /* Disable channel after done conversion */ ADCCFG &= (0x80 ^ 0xFF); /* Read the result */ reading = ADCH; reading |= (int16) (ADCH << 8); reading >>= 8; return (reading); }
6. LED燈控制函數(shù)
/**************************************************************** * 名 稱: led_opt() * 功 能: LED燈控制函數(shù) * 入口參數(shù): RxData:接收到的指令 flage:led的操作,點(diǎn)亮或者關(guān)閉 * 出口參數(shù): 無(wú) *****************************************************************/ void led_opt(char RxData[],unsigned char flage) { switch(RxData[1]) { case 1: LED1 = (flage==DEV_ID_LED_ON)?ON:OFF; break; /* TBD for led2 led3*/ default: break; } return; }
7. 主程序
/**************************************************************************** * 主程序入口函數(shù) ****************************************************************************/ void main(void) { CLKCONCMD &= ~0x40; //設(shè)置系統(tǒng)時(shí)鐘源為32MHZ晶振 while(CLKCONSTA & 0x40); //等待晶振穩(wěn)定為32M CLKCONCMD &= ~0x47; //設(shè)置系統(tǒng)主時(shí)鐘頻率為32MHZ InitLed(); //設(shè)置LED燈相應(yīng)的IO口 InitUart(); //串口初始化函數(shù) UartState = UART0_RX; //串口0默認(rèn)處于接收模式 memset(RxData, 0, SIZE); while(1) { //接收狀態(tài) if(UartState == UART0_RX) { //讀取數(shù)據(jù),遇到字符'#'或者緩沖區(qū)字符數(shù)量超過(guò)4就設(shè)置UartState為CONTROL_DEV狀態(tài) if(RxBuf != 0) { //以'#'為結(jié)束符,一次最多接收4個(gè)字符 if((RxBuf != '#')&&(count < 4)) { RxData[count++] = RxBuf; } else { //判斷數(shù)據(jù)合法性,防止溢出 if(count >= 4) { //計(jì)數(shù)清0 count = 0; //清空接收緩沖區(qū) memset(RxData, 0, SIZE); } else{ //進(jìn)入發(fā)送狀態(tài) UartState = CONTROL_DEV; } } RxBuf = 0; } } //控制控制外設(shè)狀態(tài) if(UartState == CONTROL_DEV) { //判斷接收的數(shù)據(jù)合法性 //RxData[]: | device | data |crc | # | //check_crc: crc = device ^ data //if(RxData[2] == (RxData[0]^RxData[1])) { switch(RxData[0]) { case DEV_ID_LED_ON : led_opt(RxData,DEV_ID_LED_ON); break; case DEV_ID_LED_OFF: led_opt(RxData,DEV_ID_LED_OFF); break; case DEV_ID_DELAY: break; case DEV_ID_GAS: send_gas(); break; default: break; } } UartState = UART0_RX; count = 0; //清空接收緩沖區(qū) memset(RxData, 0, SIZE); } } }
四、 上位機(jī)功能函數(shù)
結(jié)構(gòu)體
#define DEV_ID_LED_ON 0X1 #define DEV_ID_LED_OFF 0X2 #define DEV_ID_DELAY 0X3 #define DEV_ID_GAS 0X4 struct data{ unsigned char device; unsigned char crc; unsigned short data; };
函數(shù)
void uart_init(void ) { int nset1,nset2; serial_fd = open( "/dev/ttyUSB0", O_RDWR); if(serial_fd == -1) { printf("open() error\n"); exit(1); } nset1 = set_opt(serial_fd, 115200, 8, 'N', 1); if(nset2 == -1) { printf("set_opt() error\n"); exit(1); } } int Menu() { int option; system("clear"); printf("\n\t\t************************************************\n"); printf("\n\t\t** ALARM SYSTERM **\n"); printf("\n\t\t** 1----LED **\n"); printf("\n\t\t** 2----GAS **\n"); printf("\n\t\t** 0----EXIT **\n"); printf("\n\t\t************************************************\n"); while(1) { printf("Please choose what you want: "); scanf("%d",&option); if(option<0||option>2) printf("\t\t choose error!\n"); else break; } return option; } // RxData[]: | device | data |crc | # | void led() { int lednum = 0; int onoff; char cmd[4]; //選擇led燈 while(1) { printf("input led number :[1 2]\n#"); scanf("%d",&lednum); //check if(lednum<1 || lednum >2) { printf("invalid led number\n"); system("clear"); continue; }else{ break; } } printf("operation: 1 on , 0 off\n"); scanf("%d",&onoff); if(onoff == 1) { cmd[0] = DEV_ID_LED_ON; }else if(onoff == 0) { cmd[0] = DEV_ID_LED_OFF; }else{ printf("invalid led number\n"); return; } cmd[1] = lednum; //fulfill crc area cmd[2] = cmd[0]^cmd[1]; cmd[3] = '#';//表示結(jié)束符 tcflush(serial_fd, TCIOFLUSH); int i = 0; for(i=0;i<4;i++) { printf("%d ",cmd[i]); } printf("\n"); write(serial_fd,&cmd,sizeof(cmd)); sleep(1); } // RxData[]: | device | data |crc | # | void gas() { int len ; unsigned short GasLevel; struct data msg; char gas[4]={0}; char cmd[4]; cmd[0] = DEV_ID_GAS; cmd[3] = '#';//表示結(jié)束符 write(serial_fd,&cmd,sizeof(cmd)); sleep(1); len = read(serial_fd,&msg,sizeof(struct data)); //轉(zhuǎn)換讀取的gas數(shù)據(jù)格式 GasLevel = msg.data; gas[0] = GasLevel / 100 + '0'; gas[1] = GasLevel / 10%10 + '0'; gas[2] = GasLevel % 10 + '0'; printf("%s\n",gas); getchar(); } void run() { int x; while(1) { x=Menu(); switch(x) { case 1: led(); break; case 2: gas(); break; case 0: printf("\n\t\t exit!\n\n"); close(serial_fd); exit(0); default: fg=1; break; } if(fg) break; } } int main() { uart_init(); run(); return 0; }
五、 運(yùn)行結(jié)果
1. 上位機(jī)運(yùn)行界面
主菜單
2. 點(diǎn)亮led燈
點(diǎn)亮led1:
3. 滅燈
熄滅led1
4. 讀取煙霧傳感器數(shù)據(jù)
獲取煙霧數(shù)據(jù)
煙霧的數(shù)據(jù)是079,可以點(diǎn)根華子,你會(huì)發(fā)現(xiàn)每次讀取的值都是在變化。
以上是“怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。