0下用C语言实现CC2530上位机。前言网友提问如下:pipeshmmsgmessagequeue本地进程间,semsocket/unixrawsocket两台PC间:BSDsocketunix->billjoybsdbranch总结了这位网友的问题。其实就是实现一个网关程序。内容分为几个部分:下位机,通过串口与上位机连接;下位机必须能够接收上位机下发的命令并进行分析。命令;下位机可以根据这些命令配置相应的外设,读取相应传感器的数据并上传到上位机;主程序串口操作模块:通过串口下发指令或读取下位机上传的数据信息;主程序网络通讯模块:接收远程服务器下发的命令,将下位机采集的数据上传至服务器。整体来说,这相当于一个小项目,内容难度比较大。下面我们将其分成几篇独立的文章来讲解。本文只讨论如何为下位机编写一个简单的上位机。一、环境介绍1、软硬件环境下位机:CC2530操作系统:vmware+ubuntu这里彭老师使用的是CC2530,读者也可以使用其他板卡。我们只需要这块板子有一个可以和PC机通信的串口即可。有可配置的LED灯、继电器和可以收集数据的传感器。2、硬件连接图硬件连接图如下:这款CC2530集成了CH340芯片,用usb线连接电脑即可识别。3.识别PC下的串口。如果串口被PC获取,则名称为COMn[n为整数]。windows下的串口4.要识别ubuntu下的串口,vmware首先需要对串口进行抓取【串口要么被windows抓取要么被vmware同时抓取],如下图,点击连接:虚拟机抓串口ubuntu中没有ch340驱动。经实际测试,ubuntu14及之前版本没有此驱动,ubuntu16及以上版本有此驱动。如果没有ch340驱动,可以使用以下方法安装相应的驱动:1make2sudomakeload3ls/dev/ttyUSB0ubuntu安装串口驱动按照以上步骤,会生成设备文件**/dev/ttyUSB0**。ls/dev/ttyUSB0-lcrw-rw----1rootdialout188,0Jan1505:45/dev/ttyUSB0c:characterdevicerw-rw----:fileoperationpermission188,0:primaryandsecondarydevicenumber在3和4USB转串口驱动和linux驱动源码后台【GH】可回复ch340获取【注意】如果是其他开发板,请自行安装其他串口驱动。2、模块设计上位机与下位机之间的通信往往是通过串口进行的。在Linux下,经常会生成字符设备ttyUSB0【有的是ttyS0】。操作串口设备,只需要操作字符设备即可。下面我们设计上位机和下位机的软件模块。1、在上位机的信令设计中,首先要设计上位机发送给下位机的指令格式。上位机根据指令格式向下位机发送命令,下位机必须严格按照指令格式来解析指令。含义如下:device:要操作的设备data:对应的设备及其附加数据CRC:校验码#:信令终止符信令格式可以根据需要扩展或简化。设备定义如下【可根据实际情况扩展】:#defineDEV_ID_LED_ON0X1#defineDEV_ID_LED_OFF0X2#defineDEV_ID_DELAY0X3#defineDEV_ID_GAS0X4【注】为了便于理解,暂不考虑效率问题。2.上传数据下位机需要采集传感器的数据,通过串口上传。数据结构定义如下:structdata{unsignedchardevice;unsignedcharcrc;unsignedshortdata;};devicedevicedata采集到的数据的crc校验码3.功能模块现在可以设计软件的各个功能模块了。下位机的主要任务是接收上位机通过串口发来的数据,然后解析指令内容来操作相应的硬件。上位机上位机的主要任务是打印菜单,用户对菜单进行选择,然后根据指令格式封装命令,通过串口将命令发送给下位机。3、下位机功能cc2530的工作原理本文不讨论。如果是其他开发板,只需要修改串口操作函数即可。1.LED初始化/*************************************************************************************名称:InitLed()*功能:设置对应的IO口*入口参数LED灯:无*导出参数:无*************************************************************************************/voidInitLed(void){P1DIR|=0x01;//P1.0definitionFortheoutputportLED1=0;}2.初始化UART/************************************************************************名称:InitUart()*函数:串口初始化函数*入口参数:无*退出参数:无*********************************************************************/voidInitUart(void){PERCFG=0x00;//外设控制寄存器USART0的IO位置:0为P0口位置1P0SEL=0x0c;//P0_2,P0_3作为串口(外设功能)P2DIR&=~0xC0;//P0优先为UART0U0CSR|=0x80;//设置为UART模式U0GCR|=11;U0BAUD|=216;//波特率设置为115200UTX0IF=0;//UART0TX中断标志初始设置0U0CSR|=0x40;//使能接收IEN0|=0x84;//使能总中断并允许接收中断}3.串口发送功能/********************************************************************************名称:UartSendString()*功能:串口发送函数*入口参数:数据:发送缓冲区len:发送长度*出口参数:无*****************************************************************************/voidUartSendString(char*Data,intlen){uinti;for(i=0;i>=8;返回(读数);}6。LED灯控制功能/********************************************************************名称:led_opt()*功能:LED灯控制函数*入口参数:RxData:接收到的命令标志:LED操作,开或关*出口参数:无***************************************************************************/voidled_opt(charRxData[],unsignedcharflage){开关(RxData[1]){case1:LED1=(flage==DEV_ID_LED_ON)?ON:OFF;break;/*TBDforled2led3*/default:break;}return;}7.主程序/************************************************************************************主程序入口函数**********************************************************************************/voidmain(void){CLKCONCMD&=~0x40;//设置系统时钟源为32MHZ晶振while(CLKCONSTA&0x40);//等待晶振Stableto32MCLKC??ONCMD&=~0x47;//设置系统主时钟频率为32MHZInitLed();//设置LED灯对应的IO口InitUart();//串口初始化函数UartState=UART0_RX;//Serial0端口默认为接收模式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){//清计数为0count=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]){caseDEV_ID_LED_ON:led_opt(RxData,DEV_ID_LED_ON);break;caseDEV_ID_LED_OFF:led_opt(RxData,DEV_ID_LED_OFF);break;caseDEV_ID_DELAY:break;caseDEV_ID_GAS:send_gas();break;default:break;}}UartState=UART0_RX;count=0;//Clearthereceivebuffer区memset(RxData,0,SIZE);}}}四、上位机功能函数结构体#defineDEV_ID_LED_ON0X1#defineDEV_ID_LED_OFF0X2#defineDEV_ID_DELAY0X3#defineDEV_ID_GAS0X4structdata{unsignedchardevice;unsignedcharcrc;unsignedshortdata;};函数voiduart_init(void){intnset1,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);}}intMenu(){intoption;system("clear");printf("\n\t\t******************************************************\n");printf("\n\t\t**ALARMSYSTERM**\n");printf("\n\t\t**1----LED**\n");printf("\n\t\t**2----GAS**\n");printf("\n\t\t**0----退出**\n");printf("\n\t\t**************************************************\n");while(1){printf("请选择你想要的:");scanf("%d",&option);if(option<0||option>2)printf("\t\tchooseerror!\n");elsebreak;}returnoption;}//RxData[]:|device|data|crc|#|voidled(){intlednum=0;intonoff;charcmd[4];//选择led灯while(1){printf("inputlednumber:[12]\n#");scanf("%d",&lednum);//checkif(lednum<1||lednum>2){printf("invalidlednumber\n");system("clear");continue;}else{break;}}printf("operation:1on,0off\n");scanf("%d",&onoff);if(onoff==1){cmd[0]=DEV_ID_LED_ON;}elseif(onoff==0){cmd[0]=DEV_ID_LED_OFF;}else{printf("invalidlednumber\n");return;}cmd[1]=lednum;//fulfillcrareacmd[2]=cmd[0]^cmd[1];cmd[3]='#';//表示终结符tcflush(serial_fd,TCIOFLUSH);inti=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|#|voidgas(){intlen;unsignedshortGasLevel;structdatamsg;chargas[4]={0};charcmd[4];cmd[0]=DEV_ID_GAS;cmd[3]='#';//表示终结符write(serial_fd,&cmd,sizeof(cmd));sleep(1);len=read(serial_fd,&msg,sizeof(structdata));//转换要读取的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();}voidrun(){intx;while(1){x=Menu();switch(x){case1:led();break;case2:gas();break;case0:printf(“\n\t\texit!\n\n”);关闭(serial_fd);退出(0);默认:fg=1;中断;}if(fg)中断;}}intmain(){uart_init();run();return0;}五、运行结果1、上位机运行界面主菜单2、点亮led灯,点亮led1:3、熄灭灯,熄灭led14。Readsmokesensordata获取烟雾数据烟雾数据为079,可以点击GenHuazi,你会发现每次读取的值都在变化好的!至此,我们就完成了一个简单的CC2530上位机的编写。如果想将从串口获取的数据值发送到远程服务器,我们会在后续的文章中继续讨论。