您好,登錄后才能下訂單哦!
小編給大家分享一下怎么用C語言在Linux下實現CC2530上位機,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
一、環境簡介
1. 軟硬件環境
下位機:CC2530 OS:vmware + ubuntu
在這里彭老師采用的是CC2530,讀者也可以采用其他的板子,我們只需要該板子有串口,可以和PC通信,同時板子上有可設置的led燈、繼電器以及可以采集數據的傳感器即可。
2. 硬件連接圖
硬件連接圖如下:
該款CC2530已經集成了CH340芯片,usb線連接電腦,即可被識別。
3. pc下識別串口
如果該串口被PC獲取,名字為COMn【n為某整數】。
windows下串口
4. ubuntu下識別串口
首先需要vmware抓取串口【串口在同一時刻要么被windows抓取要么被vmware抓取】,按下圖所示,點擊連接即可:
虛擬機抓取串口
但是往往ubuntu中沒有ch440的驅動,經過實際測試,ubuntu14及之前的版本都沒有這個驅動,ubuntu16以上的版本有這個驅動。
如果沒有ch440驅動可以用以下方法安裝對應的驅動:
1 make 2 sudo make load 3 ls /dev/ttyUSB0
ubuntu安裝串口驅動
按照上述步驟,會生成設備文件**/dev/ttyUSB0**。
ls /dev/ttyUSB0 -l crw-rw---- 1 root dialout 188, 0 Jan 15 05:45 /dev/ttyUSB0
c : 字符設備 rw-rw---- :文件操作權限
188, 0 :主次設備號
3、4節提到的usb轉串口驅動和linux下驅動源碼后臺【GH】回復 ch440 即可獲得
【注意】如果是其他開發板,自行安裝其他的串口驅動。
二、模塊設計
上位機和下位機的通信往往都是通過串口,linux下往往生成字符設備ttyUSB0【有的是ttyS0】,操作串口設備就只需要操作該字符設備即可。
下面我們設計上下位機的軟件模塊。
1. 信令
設計上位機,首先需要設計上位機下發給下位機的指令格式,上位機按照該指令格式發送命令給下位機,下位需嚴格按照該指令格式進行解析指令。
含義如下:
device:要操作的設備
data :對應的設備及其額外的數據
CRC :校驗碼
# :信令終止符
信令格式可以根據需要擴展或者精簡。
其中device定義如下【可以根據實際情況進行擴展】:
#define DEV_ID_LED_ON 0X1 #define DEV_ID_LED_OFF 0X2 #define DEV_ID_DELAY 0X3 #define DEV_ID_GAS 0X4
【注意】為便于理解,我們暫不考慮效率問題。
2. 上傳數據
下位機需要采集傳感器的數據并通過串口上傳,數據結構定義如下:
struct data{ unsigned char device; unsigned char crc; unsigned short data; };
device 設備
data 采集的數據
crc 校驗碼
3. 功能模塊
現在就可以開始設計軟件的各個功能模塊了。
下位機
下位機流程圖
下位主要任務就是循環接收上位機通過串口下發的數據,然后解析該指令內容,操作對應的硬件。
上位機
上位機
上位機主要任務是打印菜單,由用戶針對菜單做出選擇,然后按照指令格式封裝命令,并通過串口將該命令下發給下位機。
三、 下位機功能函數
cc2530的操作原理,本文不討論,如果是其他開發板,只需要修改串口操作函數。
1. LED初始化
/**************************************************************************** * 名 稱: InitLed() * 功 能: 設置LED燈相應的IO口 * 入口參數: 無 * 出口參數: 無 ****************************************************************************/ void InitLed(void) { P1DIR |= 0x01; //P1.0定義為輸出口 LED1 = 0; }
2. 初始化UART
/**************************************************************** * 名 稱: InitUart() * 功 能: 串口初始化函數 * 入口參數: 無 * 出口參數: 無 *****************************************************************/ void InitUart(void) { PERCFG = 0x00; //外設控制寄存器 USART 0的IO位置:0為P0口位置1 P0SEL = 0x0c; //P0_2,P0_3用作串口(外設功能) P2DIR &= ~0xC0; //P0優先作為UART0 U0CSR |= 0x80; //設置為UART方式 U0GCR |= 11; U0BAUD |= 216; //波特率設為115200 UTX0IF = 0; //UART0 TX中斷標志初始置位0 U0CSR |= 0x40; //允許接收 IEN0 |= 0x84; //開總中斷允許接收中斷 }
3. 串口發送函數
/********************************************************************** * 名 稱: UartSendString() * 功 能: 串口發送函數 * 入口參數: Data:發送緩沖區 len:發送長度 * 出口參數: 無 ***********************************************************************/ void UartSendString(char *Data, int len) { uint i; for(i=0; i<len; i++) { U0DBUF = *Data++; while(UTX0IF == 0); UTX0IF = 0; } }
4. 串口中斷處理函數
/********************************************************************** * 名 稱: UART0_ISR(void) 串口中斷處理函數 * 描 述: 當串口0產生接收中斷,將收到的數據保存在RxBuf中 **********************************************************************/ #pragma vector = URX0_VECTOR __interrupt void UART0_ISR(void) { URX0IF = 0; // 清中斷標志 RxBuf = U0DBUF; }
5. 煙霧傳感器數據讀取
/**************************************************************** * 名 稱: myApp_ReadGasLevel() * 功 能: 煙霧傳感器數據讀取 * 入口參數: 無 * 出口參數: 無 *****************************************************************/ 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燈控制函數
/**************************************************************** * 名 稱: led_opt() * 功 能: LED燈控制函數 * 入口參數: RxData:接收到的指令 flage:led的操作,點亮或者關閉 * 出口參數: 無 *****************************************************************/ 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. 主程序
/**************************************************************************** * 主程序入口函數 ****************************************************************************/ void main(void) { CLKCONCMD &= ~0x40; //設置系統時鐘源為32MHZ晶振 while(CLKCONSTA & 0x40); //等待晶振穩定為32M CLKCONCMD &= ~0x47; //設置系統主時鐘頻率為32MHZ InitLed(); //設置LED燈相應的IO口 InitUart(); //串口初始化函數 UartState = UART0_RX; //串口0默認處于接收模式 memset(RxData, 0, SIZE); while(1) { //接收狀態 if(UartState == UART0_RX) { //讀取數據,遇到字符'#'或者緩沖區字符數量超過4就設置UartState為CONTROL_DEV狀態 if(RxBuf != 0) { //以'#'為結束符,一次最多接收4個字符 if((RxBuf != '#')&&(count < 4)) { RxData[count++] = RxBuf; } else { //判斷數據合法性,防止溢出 if(count >= 4) { //計數清0 count = 0; //清空接收緩沖區 memset(RxData, 0, SIZE); } else{ //進入發送狀態 UartState = CONTROL_DEV; } } RxBuf = 0; } } //控制控制外設狀態 if(UartState == CONTROL_DEV) { //判斷接收的數據合法性 //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; //清空接收緩沖區 memset(RxData, 0, SIZE); } } }
四、 上位機功能函數
結構體
#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; };
函數
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] = '#';//表示結束符 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] = '#';//表示結束符 write(serial_fd,&cmd,sizeof(cmd)); sleep(1); len = read(serial_fd,&msg,sizeof(struct data)); //轉換讀取的gas數據格式 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; }
五、 運行結果
1. 上位機運行界面
主菜單
2. 點亮led燈
點亮led1:
3. 滅燈
熄滅led1
4. 讀取煙霧傳感器數據
獲取煙霧數據
煙霧的數據是079,可以點根華子,你會發現每次讀取的值都是在變化。
以上是“怎么用C語言在Linux下實現CC2530上位機”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。