溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

發(fā)布時(shí)間:2021-10-27 11:05:20 來(lái)源:億速云 閱讀:140 作者:小新 欄目:系統(tǒng)運(yùn)維

小編給大家分享一下怎么用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. 硬件連接圖

硬件連接圖如下:

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

該款CC2530已經(jīng)集成了CH340芯片,usb線連接電腦,即可被識(shí)別。

3. pc下識(shí)別串口

如果該串口被PC獲取,名字為COMn【n為某整數(shù)】。

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

windows下串口

4. ubuntu下識(shí)別串口

首先需要vmware抓取串口【串口在同一時(shí)刻要么被windows抓取要么被vmware抓取】,按下圖所示,點(diǎn)擊連接即可:

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

虛擬機(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

 怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

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 即可獲得

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

【注意】如果是其他開發(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)行解析指令。

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

含義如下:

  • 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ī)

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

下位機(jī)流程圖

下位主要任務(wù)就是循環(huán)接收上位機(jī)通過(guò)串口下發(fā)的數(shù)據(jù),然后解析該指令內(nèi)容,操作對(duì)應(yīng)的硬件。

上位機(jī)

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(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)行界面

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

主菜單

2. 點(diǎn)亮led燈

點(diǎn)亮led1:

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

3. 滅燈

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(jī)

熄滅led1

4. 讀取煙霧傳感器數(shù)據(jù)

怎么用C語(yǔ)言在Linux下實(shí)現(xiàn)CC2530上位機(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è)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(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)容。

AI