RS232 串口通信接口和代碼實現紅綠燈控制

 

 

 

1——東西方向紅燈;

2——東西方向黃燈;

3——東西方向綠燈;

4——                       避開發送 0x0A的底層卻發送0x0D 0x0A問題

5——南北方向紅燈;

6——南北方向黃燈;

7——南北方向綠燈。

https://blog.csdn.net/qiaoliang328/article/details/6153998  0x0A的底層卻發送0x0D 0x0A問題

按上面博客鏈接修改了,但是並沒有起作用。所以我修改了接線,避開了 0x0A

1 接口頭文件

/**
  * @file      socket_uart.hpp
  * @brief 	   uart socket class
  * @author    
  * @version   1.0.0
  * @date      2019-03-27
  * @par history:
  * | version | date | author | description |
  * | ------- | ---- | ------ | ----------- |
  * | 1.0.0 | 2019-03-27 |  | create |
  */
#ifndef __SOCKET_UART_HPP_INCLUDED__
#define __SOCKET_UART_HPP_INCLUDED__

#include "socket_base.hpp"

namespace com {

class socket_uart_t : public socket_base_t {
public:

    socket_uart_t();
    ~socket_uart_t();

    void* get_sock() { return NULL; }

    int get_fd();

    int setsockopt(sock_option_t opt, const void* val, int len) { return E_NOTIMPL; }

    int getsockopt(sock_option_t opt, void *val, int* len) const { return E_NOTIMPL; }
    
    int bind(const std::string& addr);

    int unbind(const char* addr);
    
    int connect(const std::string& addr) { return E_NOTIMPL; }

    int disconnect(const char* addr) { return E_NOTIMPL; }

    void close();

    /**
      * @brief      receive data from socket 
      * @param[out]	buf     buffer of received data
      * @param[in]	len     max length of buffer
      * @param[out]	addr    receive address
      * @return     length of received data
      * @retval	    <0	    receive fail
      * @retval	    other	length of received data
      */
    int recv(void* buf, int len, std::string* addr);

    /**
      * @brief      send data on the socket 
      * @param[in]	buf     buffer of send data
      * @param[in]	len     length of buffer
      * @param[in]	addr    send address,if it is empty, the data will be send to the connected address.
      * @return     length of send data
      * @retval	    <0	    send fail
      * @retval	    other	length of send data
      */
    int send(const void* buf, int len, const std::string* addr);

    /**
      * @brief      receive message from socket 
      * @param[out] msg     received message
      * @param[in]	addr    send address,if it is empty, the data will be send to the connected address.
      * @return     length of received data
      * @retval     <0      receive fail
      * @retval     other   length of received data
      */
    int recv(socket_msg_t& msg, std::string* addr);
    
    /**
      * @brief      send msg on the socket 
      * @param[in]  msg     send message
      * @param[in]	addr    send address,if it is empty, the data will be send to the connected address.
      * @return     length of send data
      * @retval     <0      send fail
      * @retval     other   length of send data
      */
    int send(const socket_msg_t& msg, const std::string* addr);

private:
    int fd_;

};

}

#endif // __SOCKET_UART_HPP_INCLUDED__

2接口實現文件

/**
  * @file      socket_uart.cpp
  * @brief 	   uart socket class
  * @author    xxxxxxxxxxx
  * @version   1.0.0
  * @date      2019-03-27
  * @par history:
  * | version | date | author | description |
  * | ------- | ---- | ------ | ----------- |
  * | 1.0.0 | 2019-03-27 | xxxxxx | create |
  */
#include "socket_uart.hpp"
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>

namespace com {

socket_uart_t::socket_uart_t()
{
    fd_ = 0;
}

socket_uart_t::~socket_uart_t()
{
    close();
}

int socket_uart_t::get_fd()
{
    return fd_;
}

int socket_uart_t::bind(const std::string& addr)
{
    std::cout<<"socket_uart_t::bind:"<<std::endl;
	int ret = E_OK;
    sock_protocol_t prot_type;
    std::string name;
    int baud = 9600;
    int c_flow = 0;
    int bits = 8;
    char parity = 'N';
    int stop = 1;

    do
    {
        if (addr.empty())
        {
            ret = E_INVAL;
            break;
        }

        // have bound
        if (fd_ > 0)
        {
            ret = E_ALREADY;
            break;
        }

        // parse address
        prot_type = parse_addr(addr, name, &baud);
		prot_type = SOCK_PROTOCOL_UART;
		name="/dev/ttymxc2";
        if (SOCK_PROTOCOL_UART != prot_type)
        {
            ret = E_NOTSUPT;
            break;
        }       
        
        // open uart
        ret = open(name.c_str(), O_RDWR|O_NOCTTY|O_NDELAY);
        if(-1 == ret)
        {
            ret = E_OPENFAIL;
            break;
        }
		std::cout<<"open uart fd_ =ret= "<<ret<<std::endl;
        fd_ = ret;
    
        // clear the nonblocking flag
        //恢復串口狀態爲阻塞,用於等待串口數據的讀入
        if(fcntl(fd_, F_SETFL, 0) < 0)
        {
            ret = socket_error_t::trans_syserr();
            break;
        }
        
        struct termios options;
        
        // get attribute 
        if(tcgetattr(fd_,&options) < 0)
        {
            ret = socket_error_t::trans_syserr();
            break;
        }
        
        // set the input/output baud rate
        switch(baud)
        {
            case 4800:
                cfsetispeed(&options, B4800);
                cfsetospeed(&options, B4800);
                break;
            case 9600:
                cfsetispeed(&options, B9600);
                cfsetospeed(&options, B9600);
                break;
            case 19200:
                cfsetispeed(&options, B19200);
                cfsetospeed(&options, B19200);
                break;
            case 38400:
                cfsetispeed(&options, B38400);
                cfsetospeed(&options, B38400);
                break;
            case 57600:
                cfsetispeed(&options, B57600);
                cfsetospeed(&options, B38400);
                break;
            case 115200:
                cfsetispeed(&options, B115200);
                cfsetospeed(&options, B115200);
                break;
            default:
                ret = E_INVAL;
                break;
        }
        if (ret)
        {
            break;
        }
        
        // set control mode
        options.c_cflag |= CLOCAL;  // not occupy the serial port
        options.c_cflag |= CREAD;   // can read data
        
        // set data flow control
        switch(c_flow)
        {
            case 0:     //不進行流控制
                options.c_cflag &= ~CRTSCTS;
                break;
            case 1:     //進行硬件流控制
                options.c_cflag |= CRTSCTS;
                break;
            case 2:     //進行軟件流控制
                options.c_cflag |= IXON|IXOFF|IXANY;
                break;
            default:
                ret = E_INVAL;
                break;
        }
        if (ret)
        {
            break;
        }
        
        // set data bits
        switch(bits)
        {
            case 5:
                options.c_cflag &= ~CSIZE;//屏蔽其它標誌位
                options.c_cflag |= CS5;
                break;
            case 6:
                options.c_cflag &= ~CSIZE;//屏蔽其它標誌位
                options.c_cflag |= CS6;
                break;
            case 7:
                options.c_cflag &= ~CSIZE;//屏蔽其它標誌位
                options.c_cflag |= CS7;
                break;
            case 8:
                options.c_cflag &= ~CSIZE;//屏蔽其它標誌位
                options.c_cflag |= CS8;
                break;
            default:
                ret = E_INVAL;
                break;
        }
        if (ret)
        {
            break;
        }
        
        // set parity bit
        switch(parity)
        {
            /*無奇偶校驗位*/
            case 'n':
            case 'N':
                options.c_cflag &= ~PARENB;//PARENB:產生奇偶位,執行奇偶校驗
                options.c_cflag &= ~INPCK;//INPCK:使奇偶校驗起作用
                break;
            /*設爲空格,即停止位爲2位*/
            case 's':
            case 'S':
                options.c_cflag &= ~PARENB;//PARENB:產生奇偶位,執行奇偶校驗
                options.c_cflag &= ~CSTOPB;//CSTOPB:使用兩位停止位
                break;
            /*設置奇校驗*/
            case 'o':
            case 'O':
                options.c_cflag |= PARENB;//PARENB:產生奇偶位,執行奇偶校驗
                options.c_cflag |= PARODD;//PARODD:若設置則爲奇校驗,否則爲偶校驗
                options.c_cflag |= INPCK;//INPCK:使奇偶校驗起作用
                options.c_cflag |= ISTRIP;//ISTRIP:若設置則有效輸入數字被剝離7個字節,否則保留全部8位
                break;
            /*設置偶校驗*/
            case 'e':
            case 'E':
                options.c_cflag |= PARENB;//PARENB:產生奇偶位,執行奇偶校驗
                options.c_cflag &= ~PARODD;//PARODD:若設置則爲奇校驗,否則爲偶校驗
                options.c_cflag |= INPCK;//INPCK:使奇偶校驗起作用
                options.c_cflag |= ISTRIP;//ISTRIP:若設置則有效輸入數字被剝離7個字節,否則保留全部8位
                break;
            default:
                ret = E_INVAL;
                break;
        }
        if (ret)
        {
            break;
        }
        
        // set stop bit
        switch(stop)
        {
            case 1:
                options.c_cflag &= ~CSTOPB;//CSTOPB:停止位爲1
                break;
            case 2:
                options.c_cflag |= CSTOPB;//CSTOPB:使用停止位爲2
                break;
            default:
                ret = E_INVAL;
                break;
        }
        if (ret)
        {
            break;
        }
        
        /*設置輸出模式爲原始輸出*/
      //options.c_oflag &= ~OPOST;//OPOST:若設置則按定義的輸出處理,否則所有c_oflag失效
        options.c_iflag &= ~(INLCR | ICRNL | IGNCR);//解決發送)0X0A的問題
        options.c_oflag &= ~(ONLCR | OCRNL | ONOCR | ONLRET); 
        /*設置本地模式爲原始模式*/
        options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
        /*
         *ICANON:允許規範模式進行輸入處理
         *ECHO:允許輸入字符的本地回顯
         *ECHOE:在接收EPASE時執行Backspace,Space,Backspace組合
         *ISIG:允許信號
         */
    
        /*設置等待時間和最小接受字符*/
        options.c_cc[VTIME] = 0;//可以在select中設置
        options.c_cc[VMIN] = 1;//最少讀取一個字符
    
        /*如果發生數據溢出,只接受數據,但是不進行讀操作*/
        tcflush(fd_,TCIFLUSH);
    
        /*激活配置*/
        if(tcsetattr(fd_,TCSANOW,&options) < 0)
        {
            ret = socket_error_t::trans_syserr();
            break;
        }
        
    } while(0);

    if (ret < 0)
    {
        unbind(NULL);
    }

    return ret;
}

int socket_uart_t::unbind(const char* addr)
{
    if (fd_)
    {
        ::close(fd_);
        fd_ = 0;
    }
    return E_OK;
}

void socket_uart_t::close()
{
    unbind(NULL);
}

int socket_uart_t::send(const void* buf, int len, const std::string* addr)
{
    int ret = E_OK;

    do
    {
        std::cout<<"socket_uart_t::send begin!"<<std::endl;
		if ((NULL == buf) || 
            (len <= 0))
        {
            ret = E_INVAL;
            break;
        }
        std::cout<<"socket_uart_t send fd_: "<<fd_<<std::endl;
        if (fd_ <= 0)
        {
            ret = E_NOTINIT;
            break;
        }

        
        int left = len;
        const char* ptr = (const char*)buf;
		std::cout<<"uart data:";
        for(int i=0 ; i<8 ; i++)
        {
		    printf("%X ",ptr[i]);
        }
		std::cout<<std::endl;
        while(left > 0)
        {
            std::cout<<"socket uart  write begin..."<<std::endl;
			ret = write(fd_, ptr, left);
			std::cout<<"socket uart  write end ret: "<<ret<<std::endl;
            if(ret <= 0)
            {
                if((ret < 0) &&
                   (errno == EINTR))
                {
                    ret = 0;
                }
                else
                {
                    ret = socket_error_t::trans_syserr();
                    break;
                }
            }
            left -= ret;
            ptr += ret;
        }
        
    } while(0);

    return ret;
}

int socket_uart_t::recv(void* buf, int len, std::string* addr)
{
    int ret = E_OK;

    do
    {
        if ((NULL == buf) || 
            (len <= 0))
        {
            ret = E_INVAL;
            break;
        }

        if (fd_ <= 0)
        {
            ret = E_NOTINIT;
            break;
        }

        ret = read(fd_, buf, len);
        if(ret < 0)
        {
            if(errno == EINTR)//被信號中斷
            {
                ret = 0;
            }
            else
            {
                ret = socket_error_t::trans_syserr();
                break;
            }
        }

    } while(0);

    return ret;
}

int socket_uart_t::send(const socket_msg_t& msg, const std::string* addr)
{
    return send(msg.data(), msg.size(), addr);
}

int socket_uart_t::recv(socket_msg_t& msg, std::string* addr)
{
    int ret = E_OK;

    do
    {

        if (fd_ <= 0)
        {
            ret = E_NOTINIT;
            break;
        }

        char buf[64] = {0};

        ret = recv(buf, sizeof(buf), addr);
        if (ret > 0)
        {
            msg.build(buf, ret);
        }
    } while(0);

    return ret;
}

};

 

上面的接口文件實際測試有用,接下來,編寫代碼來使用接口

1綁定串口


int appi_spat_t::bind_uart(std::string& addr)
{
    int ret=E_INVAL;
	std::cout<<"bind  uart start"<<std::endl;
	log_->info("bind_uart start");
	ret=socket_uart_.bind(addr);
	log_->info("bind_uart ret:%d ",ret);
	std::cout<<"bind  uart ret:"<<ret<<std::endl;
	if(E_INVAL ==ret)
    {
       log_->error("bind_uart failed!");
	}
	return ret;
   
}

 

2、根據通信協議 組數據包

int appi_spat_t::get_uart_light(int phase1_light,int phase2_light)
{
     //根據紅綠燈串口協議組一個串口幀
     int ret = E_OK;
	 uart_rx_data_[0]=0x33;
	 uart_rx_data_[1]=0x01;
	 uart_rx_data_[2]=0x16;
	 uart_rx_data_[3]=0x00;
	 uart_rx_data_[4]=0x00;
	 uart_rx_data_[6]=0x08;
	 
	 if(( TRA_LIGHT_STATE_RED == phase1_light) &&  //3
	   (TRA_LIGHT_STATE_GREEN == phase2_light))    //5
	 {
          uart_rx_data_[5]=0x41;//100 0001
		  uart_rx_data_[7]=0x93;

	 }
     if(( TRA_LIGHT_STATE_RED == phase1_light) &&   //3
	   (TRA_LIGHT_STATE_YELLOW == phase2_light))    //7
     {
          uart_rx_data_[5]=0x21;//010 0001
		  uart_rx_data_[7]=0x73;

     }

	 if(( TRA_LIGHT_STATE_RED == phase2_light) &&   //3
	   (TRA_LIGHT_STATE_GREEN == phase1_light))     //5
	 {
          uart_rx_data_[5]=0x14;//001 0100
		  uart_rx_data_[7]=0x66;
		 
	 }
     if(( TRA_LIGHT_STATE_RED == phase2_light) &&   //3
	   (TRA_LIGHT_STATE_YELLOW == phase1_light))    //7
     {
		  uart_rx_data_[5]=0x12;//001 0010
		  uart_rx_data_[7]=0x64;  
     }
	 if(uart_rx_data_[5] <= 0)
	 {
         log_->error("get_uart_light fault!");
		 ret = E_FALT;
	 }
	 log_->info("get uart light data_: %X",uart_rx_data_[5]);
	
     return ret;
}

 組報文的方法二

void appi_spat_t::get_uart_light(int phase1_light,int phase2_light)
{    //根據紅綠燈串口協議組一個串口幀
     
	 uart_rx_data_[0]=0x33;
	 uart_rx_data_[1]=0x01;
	 uart_rx_data_[2]=0x16;
	 uart_rx_data_[3]=0x00;
	 uart_rx_data_[4]=0x00;
	 uart_rx_data_[6]=0x08;
	 switch(phase1_light)
     {
	 	case TRA_LIGHT_STATE_RED:  //3
			
     	{
            switch(phase2_light)
            {
	 	        case TRA_LIGHT_STATE_RED:
     	        {
                      log_->error("get_uart_light fault!");
					  ret = E_FALT;
                      break;
		        }
		        case TRA_LIGHT_STATE_YELLOW:  //7
		        {
                      //char buff[]="0X33 0X01 0X16 0X00 0X00 0X11 0X08 0X63";//010 001
                      
					  uart_rx_data_[5]=0x11;//010 001
					  uart_rx_data_[7]=0x63;
                      break;
		        }
                case TRA_LIGHT_STATE_GREEN:   //5
                {
                       //char buff[]="0X33 0X01 0X16 0X00 0X00 0X21 0X08 0X73";//100 001
                       uart_rx_data_[5]=0x21;//100 001
					   uart_rx_data_[7]=0x73;
		               break;
		        }
             }   
            break;
		}
		
		case TRA_LIGHT_STATE_YELLOW:    //7
		{
		    switch(phase2_light)
            {
	 	        case TRA_LIGHT_STATE_RED:   //3
     	        {
                      //char buff[]="0X33 0X01 0X16 0X00 0X00 0X0A 0X08 0X5C";//001 010
                      uart_rx_data_[5]=0x0A;//001 010
					  uart_rx_data_[7]=0x5C;
                      break;
		        }
		        case TRA_LIGHT_STATE_YELLOW:
		        {
                      log_->error("get_uart_light fault!");
					  ret = E_FALT;
                      break;
		        }
                case TRA_LIGHT_STATE_GREEN:    //5
                {
                       //char buff[]="0X33 0X01 0X16 0X00 0X00 0X22 0X08 0X74";//100 010
                       uart_rx_data_[5]=0x22;//100 010
					   uart_rx_data_[7]=0x74;
		               break;
		        }
             }   

            break;
		}
		
        case TRA_LIGHT_STATE_GREEN:   //5
        {
            switch(phase2_light)
            {
	 	        case TRA_LIGHT_STATE_RED:   //3
     	        {
                      //char buff[]="0X33 0X01 0X16 0X00 0X00 0X0C 0X08 0X5E";//001 100
                      uart_rx_data_[5]=0x0C;//001 100
					  uart_rx_data_[7]=0x5E;
                      break;
		        }
		         case TRA_LIGHT_STATE_YELLOW:  //7
		         {
                      //char buff[]="0X33 0X01 0X16 0X00 0X00 0X14 0X08 0X66";//010 100
                      uart_rx_data_[5]=0x14;//010 100
					  uart_rx_data_[7]=0x66;
                      break;
		         }
                 case TRA_LIGHT_STATE_GREEN:
                 {                       
                      log_->error("get_uart_light fault!");
					  
		              break;
		         }
             } 
			
			
		    break;
		}
	}
	log_->info("get uart light data_: %X",uart_rx_data_[5]);
	
     return ;
}

3、向串口發送

int appi_spat_t::send_uart(const void* buf, int len, const std::string* addr)
{  
    int ret=E_INVAL;
	std::cout<<"socket_uart  send"<<std::endl;
	ret=socket_uart_.send(buf,len,addr);
	std::cout<<"socket_uart  send ret: "<<ret<<std::endl;
	if(E_INVAL ==ret)
    {
       log_->error("send_uart failed!");
	}
	return ret;
}

我並沒有寫發送返回檢查程序,串口發送報文,接收模塊會根據協議返回對應的返回碼,

根據返回碼,可以知道發送的報文是否正確

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章