challis 发表于 2024-2-3 12:23:18

简单的上位机串口控制单片机

测试使用上位机提供web服务,通过串口来控制单片机

challis 发表于 2024-2-3 12:25:07

单片机使用STC8H8K64U,上位机使用的是golang语言,最终效果如下

challis 发表于 2024-2-3 12:26:36

单片机的程序可以参照,实现了简单的串口通信以及串口数据处理
STC8H8K64U-软件实现串口不断电烧录程序

challis 发表于 2024-2-3 12:28:17

串口数据处理函数中,如果收到hello 则返回world!,如果收到0x0f,则将P1端口设置为接收到的第二位数据
void DealString(char *p)
{
    if(p == 0x0f)
    {
      P1 = p;
      UartSendStr("p1");
    }else if(strcmp(p,"p1")==0)
    {
      UartSend(P1);
    }
    else if(strcmp(p,"hello") == 0)
    {
      UartSendStr("world!");
    }
    else if(strcmp(p,"reboot") == 0)
    {
      Delay_ms(1000);
      UartSendStr("bye!");
      IAP_CONTR = 0x60;
    }
    else if(strncmp(p,"seg",3) == 0)
    {
      STC_SEG7_ShowString(p+3);
    }
    else if (strcmp(p,"led40") == 0)
    {
      Test_STC_LED40();
    }
    else
    {
      UartSendStr(p);
    }
}

challis 发表于 2024-2-3 12:29:27

完整的单片机代码和golang源码:

challis 发表于 2024-2-3 12:37:54

golang上封装下串口操作,使用github.com/jacobsa/go-serial/serial包,实现了打开串口,收发数据,以及关闭串口
package myfun

import (
        "errors"
        "io"

        "github.com/jacobsa/go-serial/serial"
)

var _port io.ReadWriteCloser = nil
var _options = serial.OpenOptions{
        PortName:            "",
        BaudRate:            19200,
        DataBits:            8,
        StopBits:            1,
        MinimumReadSize:       4,
        InterCharacterTimeout: 500,
}

func OpenPort(port_name string) error {
        if _port != nil {
                _port.Close()
        }

        var err error
        _options.PortName = port_name
        _port, err = serial.Open(_options)
        if err != nil {
                _port = nil
        }
        return err
}

func SendAndRecv(msg string) (string, error) {
        if _port == nil {
                return "", errors.New("请先打开串口")
        }
        bts := []byte(msg)
        _, err := _port.Write(bts)
        if err != nil {
                return "", err
        }
        buff := make([]byte, 128)
        n, err := _port.Read(buff)
        if err != nil {
                return "", err
        }
        return string(buff[:n]), nil
}

func SendAndRecv_bts(msg []byte) ([]byte, error) {
        if _port == nil {
                return nil, errors.New("请先打开串口")
        }
        _, err := _port.Write(msg)
        if err != nil {
                return nil, err
        }
        buff := make([]byte, 128)
        _, err = _port.Read(buff)
        if err != nil {
                return nil, err
        }
        return buff, nil
}
func ClosePort() error {
        if _port != nil {
                return _port.Close()
        }
        return nil
}

challis 发表于 2024-2-3 12:38:50

使用gin搭建web服务,实现web调用打开串口,开灯,关灯和hello的响应
package myfun

import (
        "fmt"

        "github.com/gin-gonic/gin"
)

func _send(c *gin.Context, msg string) {
        c.JSON(200, gin.H{
                "msg": msg,
        })
}

func Gin_OpenCom(c *gin.Context) {
        com_name := c.Query("c")
        if len(com_name) <= 0 {
                _send(c, "COM口异常")
                return
        }
        err := OpenPort(com_name)
        if err == nil {
                _send(c, "COM口打开成功!")
        } else {
                _send(c, err.Error())
        }
}

func Gin_LedOn(c *gin.Context) {
        _, err := SendAndRecv_bts([]byte{0x0f, 0x00})
        if err != nil {
                _send(c, err.Error())
        } else {
                _send(c, "开灯 - 操作成功")
        }
}

func Gin_LedOff(c *gin.Context) {
        _, err := SendAndRecv_bts([]byte{0x0f, 0xff})
        if err != nil {
                _send(c, err.Error())
        } else {
                _send(c, "关灯 - 操作成功")
        }
}

func Gin_Hello(c *gin.Context) {
        msg, err := SendAndRecv("hello")
        fmt.Println(msg)
        if err != nil {
                _send(c, err.Error())
        } else {
                _send(c, msg)
        }
}

challis 发表于 2024-2-3 12:39:45

简单写一个控制网页,使用XMLHttpRequest来后台发送获取数据
<!DOCTYPE html>
<html>
    <head></head>
    <body>
      <div><p id="msg"></p></div>
      <div>
            串口:
            <select id="com_select">
                <option value="COM1">COM1</option>
                <option value="COM2">COM2</option>
                <option value="COM3">COM3</option>
                <option value="COM4">COM4</option>
                <option value="COM5">COM5</option>
                <option value="COM6">COM6</option>
                <option value="COM7">COM7</option>
                <option value="COM8">COM8</option>
                <option value="COM9">COM9</option>
            </select>
            <button id="com_btn" onclick="open_com()">打开串口</button>
      </div>
      <br />
      <div>
            <button id="hello_btn" onclick="hello()">hello</button>
            <button id="led_open_btn" onclick="led_on()">开灯</button>
            <button id="led_close_btn" onclick="led_off()">关灯</button>
      </div>
      <script type="text/javascript">
            xmlhttp = new XMLHttpRequest()
            xmlhttp.onreadystatechange = function()
            {
                if(xmlhttp.readyState==4 && xmlhttp.status==200)
                {
                  var res = JSON.parse(xmlhttp.responseText)
                  document.getElementById("msg").innerText = res.msg;
                }
            }
            function open_com(){
                var v = document.getElementById("com_select").value
                xmlhttp.open("GET","/open_com?c="+v,true)
                xmlhttp.send()
            }
            function led_on(){
                xmlhttp.open("GET","/led_on",true)
                xmlhttp.send()
            }
            function led_off(){
                xmlhttp.open("GET","/led_off",true)
                xmlhttp.send()
            }
            function hello(){
                xmlhttp.open("GET","/hello",true)
                xmlhttp.send()
            }
      </script>
    </body>
</html>

challis 发表于 2024-2-3 12:41:01

如果需要手机访问,可以修改主函数中gin监听的ip如下即可
func main() {
        r := gin.Default()
        r.GET("ping", pong)
        r.GET("open_com", myfun.Gin_OpenCom)
        r.GET("led_on", myfun.Gin_LedOn)
        r.GET("led_off", myfun.Gin_LedOff)
        r.GET("hello", myfun.Gin_Hello)

        r.StaticFile("uart.html", "html/index.html")
        r.Run(":12345")
        fmt.Println("Hello")
}

challis 发表于 2024-2-3 12:46:04

手机上访问http://上位机ip:12345/uart.html则可进行控制了
页: [1] 2
查看完整版本: 简单的上位机串口控制单片机