怎么用C语言在Linux下实现CC2530上位机

86次阅读
没有评论

共计 7503 个字符,预计需要花费 19 分钟才能阅读完成。

丸趣 TV 小编给大家分享一下怎么用 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  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 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 上位机”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注丸趣 TV 行业资讯频道!

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-25发表,共计7503字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)