Labwindows CVI写上位机与STM32下位机通信(一)

来源:互联网 发布:那个程序员txt总攻大人 编辑:程序博客网 时间:2024/05/17 08:14

    最近在用Labwindows CVI写一个多串口的上位机程序,主要实现如下功能:(1) 上位机与下位机STM32通信,上位机通过串口发送控制命令(LED矩阵图形选择、电磁阀控制信号)给下位机,下位机回发控制信息。(2)上位机通过modbus通信协议485通信接口,读取MEMS流量计瞬时流量和总流量数据,并显示到面板上。

    一. STM32下位机

    考虑到LED矩阵面板上有40*10个LED,要控制每只LED的亮灭来显示不同图案,这样就需要至少需要50个IO口,之所以选择STM32做下位机是因为STM32F407的GPIO达到96个,出去JTAG等一些固定用处的GPIO外,我们的板子引出了66个可自由使用的GPIO。

    1.1 驱动电路

    选好控制器后,我们发现当LED全亮时,电路上流过的电流会很大,假设每个LED亮时的功率为10mW,全亮的情况下功率达到了4W,STM32的GPIO最大输出电流不超过25mA,因此不能直接使用GPIO驱动,而且LED矩阵的电流不能通过STM32到地,否则会烧坏器件。最终我们选择如下驱动电路:

图1. 大电流(1A左右)驱动电路

电路中NPN管S9013极限输出电流可达500mA,当一列LED全亮时(10个),电流大概50mA;PNP管子S8550极限输出电流700mA,当一行LED全亮时,电流大概200mA,满足要求;选用这种结构的驱动电路有两个作用:(1)电流放大,提高驱动能力。(2)GPIO只控制管子的基极,但GPIO采用上拉输出,上拉电阻20K~50K,流过GPIO的电流很小,起到隔离大电流作用。

    1.2 下位机编程


   

  二.Labwindows CVI上位机

    之前用过Labwindows CVI写TCP服务器作为上位机,这次试用串口通信;综合整个工程考虑,与下位机通信要用一个串口,读流量计数据要用两个串口(两个流量计),因此需要3个串口端口。上位机截图如下:

2.1 Labwindows CVI串口通信编程:

    (1)配置串口,建立串口端口函数   

//配置uartint CVICALLBACK PortEnable (int panel, int control, int event,        void *callbackData, int eventData1, int eventData2){    switch (event)    {        case EVENT_COMMIT:  //注意:多次打开串口会出错            uartPort.port_open = 0; //未打开            GetCtrlVal(panelHandle,PANEL_PORT_NUM,&uartPort.portNum); //获取端口号            GetCtrlIndex(panelHandle,PANEL_PORT_NUM,&uartPort.portIndex);            GetLabelFromIndex(panelHandle,PANEL_PORT_NUM,uartPort.portIndex,uartPort.deviceName);            DisableBreakOnLibraryErrors();                 uartPort.RS232Error = OpenComConfig(uartPort.portNum,uartPort.deviceName,115200,0,8,1,512,512); //STM32控制,打开串口            EnableBreakOnLibraryErrors();            if(uartPort.RS232Error == 0)  //串口打开成功            {                uartPort.port_open = 1;                SetXMode(uartPort.portNum,0); //关闭XOFF                SetCTSMode(uartPort.portNum,0);                SetComTime(uartPort.portNum,5);                SetCtrlVal(panelHandle,PANEL_UART_LED,1); //点亮指示灯                //清空串口的TxBuffer、RxBuffer                FlushInQ(uartPort.portNum);                FlushOutQ(uartPort.portNum);                                //建立串口回调函数                InstallComCallback(uartPort.portNum,LWRS_RXFLAG,0,10,UartComCallback,0);  //以回车为标志位,接收到回车就产生中断,调用中断函数UartComCall.            }            else            {                MessagePopup("Error","该COM口已被占用,请选择其他COM口!");                SetCtrlVal(panelHandle,PANEL_UART_LED,0); //关闭指示灯                uartPort.port_open = 0;            }            break;    }    return 0;}
查看CVI中给的API知道:调用
int InstallComCallback (int Port_Number, int Event_Mask, int Notify_Count, int Event_Character, ComCallbackPtr Callback_Function, void *Callback_Data);
可建立端口回调函数,注意参数:

  --eventMask :可取LWRS_RXCHARLWRS_RXFLAG,LWRS_RECEIVE等;其中LWRS_RXCHAR表示接收1个字符放入到输入队列时就执行回调函数,但是当接收到一个字符串时,并不会每接收一个字符就调用一次回调函数;LWRS_RXFLAGS与Event_Character配合,当接收序列中有Event_Character时就会执行回调函数;LWRS_RECEIVE与notifyCount配合使用,当接收缓存中至少有notifyCount Byte个数据时,就执行回调函数,即每接收notifyCount个数据就执行一次回调函数。

--callbackFunction: 回调函数名   

    (2)编写端口回调函数

回调函数相当于串口中断函数,只是没有中断优先级这种的说法,只要满足执行条件就会触发回调函数执行,但回调函数的执行不能打断正在其他的其他程序,要等其他程序执行完才能执行。

//发送一个char数据void SendByte(portInfo port,char ch){    if(port.port_open == 0)        MessagePopup("Error","串口还未打开!");    else    {        FlushOutQ(port.portNum);  //清空发送缓存区        ComWrt(port.portNum,&ch,sizeof(ch));    }}void CVICALLBACK UartComCallback(int portNo, int eventMask, void *callbackData){    char readBuf[256] = {0};    int strLen;    strLen = GetInQLen(uartPort.portNum);    ComRd(uartPort.portNum,readBuf,strLen);        SetCtrlVal(panelHandle,PANEL_RECEIVE_MESSAGE,readBuf);}


0 0
原创粉丝点击