5.2_帧速率的计算

5.2_帧速率的计算

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>帧速率的计算</title>
        <style>
            body{
                background: #ddd;
            }
            #canvas{
                background: #fff;
                cursor: pointer;
                margin-left: 10px;
                margin-top: 10px;
                -webkit-box-shadow: 3px 3px 6px rgba(0,0,0,0.5);
                -moz-box-shadow: 3px 3px 6px rgba(0,0,0,0.5);
                box-shadow: 3px 3px 6px rgba(0,0,0,0.5);
            }
            #controls{
                margin-top: 10px;
                margin-left: 15px;
            }
        </style>
    </head>
    <body>
        <div id="controls">
            <input id="animateButton" type="button" value="Animate" />
        </div>

        <canvas id="canvas" width="750" height="500"></canvas>

    </body>
    <script>
        var canvas = document.getElementById('canvas');
        var context = canvas.getContext('2d');
        var paused = true; 
        var discs = [ //三个圆的各种属性
            {
                x:150,
                y:250,
                lastX:150,
                lastY:250,
                velocityX:-3.2,
                velocityY:3.5,
                radius:25,
                innerColor:'rgba(255,255,0,1)',
                middleColor:'rgba(100,145,230,0.7)',
                outerColor:'rgba(100,145,230,0.5)',
                strokeStyle:'gray'
            },
            {
                x:50,
                y:150,
                lastX:50,
                lastY:150,
                velocityX:2.2,
                velocityY:2.5,
                radius:25,
                innerColor:'rgba(100,145,230,1)',
                middleColor:'rgba(100,145,230,0.7)',
                outerColor:'rgba(100,145,230,0.5)',
                strokeStyle:'blue'
            },
            {
                x:150,
                y:75,
                lastX:150,
                lastY:75,
                velocityX:1.2,
                velocityY:1.5,
                radius:25,
                innerColor:'rgba(255,0,0,1)',
                middleColor:'rgba(255,0,0,0.7)',
                outerColor:'rgba(255,0,0,0.5)',
                strokeStyle:'orange'
            },
        ];

        var numDiscs = discs.length;
        var animateButton = document.getElementById('animateButton');
        var lastTime = 0;

        //初始化
        context.font = '48px Helvetica';
        drawBackground();
        //事件控制
        animateButton.onclick = function(){
            paused = paused? false:true; 
            if(paused){  //如果停止动画
                animateButton.value = 'Animate';
            }else{ //播放动画
                window.requestAnimationFrame(animate);
                animateButton.value = 'Pause';
            }
        }

        //执行每次动画效果
        function animate(time){
            if(!paused){
                context.clearRect(0,0,canvas.width,canvas.height);//每帧清空一次画布
                drawBackground();
                update(); //更新此帧的三个圆的各种新属性
                drawCircles();//开始绘制更新后的圆

                //绘制帧速率
                context.fillStyle = 'cornflowerblue';
                context.fillText(calculateFps().toFixed()+'fps',20,60);
                //执行下一次animate
                window.requestAnimationFrame(animate);
            }
        }
        //绘制帧速率
        function calculateFps(){
             //这里会有一个加号是因为一元+操作符会有Number()转型函数的功能,将时间对象转换到数字类型的秒数,以便后续计算
            var now = +(new Date);
            //console.log(new Date);
            //console.log(now);
            var fps = 1000/(now - lastTime);

            lastTime = now;

            return fps;
        }
        //更新
        function update(){
            var disc;
            for(var i=0;i<numDiscs;i++){
                disc = discs[i];

                if(disc.x+disc.radius+disc.velocityX>context.canvas.width || disc.x-disc.radius+disc.velocityX<0){
                    disc.velocityX = -disc.velocityX;
                }
                if(disc.y+disc.radius+disc.velocityY>context.canvas.height || disc.y-disc.radius+disc.velocityY<0){
                    disc.velocityY = -disc.velocityY;
                }
                disc.x += disc.velocityX;
                disc.y += disc.velocityY;

            }
        }
        //绘制更新后的圆
        function drawCircles(){
            var disc;
            var gradient;
            for(var i=0;i<numDiscs;i++){
                disc = discs[i];

                gradient = context.createRadialGradient(disc.x,disc.y,0,disc.x,disc.y,disc.radius);
                gradient.addColorStop(0.3,disc.innerColor);
                gradient.addColorStop(0.5,disc.middleColor);
                gradient.addColorStop(1.0,disc.outerColor);

                context.save();
                context.beginPath();
                context.arc(disc.x,disc.y,disc.radius,0,Math.PI*2,false);
                context.fillStyle = gradient;
                context.strokeStyle = disc.strokeStyle;
                context.fill();
                context.stroke();
                context.restore();

            }
        }
        //绘制横隔背景
        function drawBackground(){
            context.save();
            context.shadowColor = undefined;
            context.shadowOffsetX = 0;
            context.shadowOffsetY = 0;
            context.shadowBlur = 0;

            var step_y = 12;
            var left_margin = step_y*4;
            var top_margin = step_y*3;
            var i = canvas.height;

            context.strokeStyle = 'lightgray';
            context.lineWidth = 0.5;

            while(i>top_margin){
                context.beginPath();
                context.moveTo(0,i);
                context.lineTo(canvas.width,i);
                context.stroke();
                i-=step_y;
            }

            context.restore();
        }
    </script>
</html>
<think>好的,我现在需要帮助用户解决基于STC8H8K64U单片机的串口通信程序及架构设计,解析GNGGA北斗数据并转换为经纬度高度信息,同时提供完整代码和原理图。首先,我需要整理用户的需求,确保覆盖所有要点:串口2和串口4的配置,波特率115200,解析GNGGA数据,提取经纬度和高度,转换为实际数值,并提供代码和原理图。 首先,我应该回顾STC8H8K64U的串口配置方法。这款单片机有多个串口,用户提到了串口2和串口4。需要查阅数据手册,确认这两个串口的寄存器配置方式。波特率115200,需要计算对应的定时器重装值,确保通信速率正确。可能涉及定时器1或定时器2的使用,具体要看串口的工作模式。 接下来是GNGGA数据的解析。GNGGA是GNSS定位信息的主要语句,包含经纬度、高度、卫星数等数据。需要了解该语句的结构,例如字段之间的逗号分隔,各个字段的含义。例如,纬度格式通常是度分格式,需要转换为十进制度,可能需要分割字符串,处理小数点位置。 然后要考虑如何从串口接收数据。通常使用中断方式接收,设置接收缓冲区,存储接收到的字符。当检测到帧头“$GNGGA”时开始记录数据,直到遇到换行符结束。需要处理数据的分割和校验,可能需要计算校验和,确保数据完整性。 转换为实际经纬度和高度时,要注意纬度和经度的格式转换。例如,纬度数据可能是“ddmm.mmmm”格式,需要将其拆分为度和分部分,然后将分转换为小数度。南纬和西经需要用负数表示。高度数据通常以米为单位,直接转换即可。 代码部分需要包括串口初始化函数、中断服务程序、数据解析函数以及主程序逻辑。需要注意单片机的资源分配,例如使用哪个定时器作为波特率发生器,是否需要开启中断优先级,避免数据丢失。 原理图设计需要包括单片机的串口引脚连接,可能使用P1.0和P1.1作为串口2,P0.2和P0.3作为串口4。电平转换电路(如MAX232或CH340)可能也需要,但用户可能已经有硬件设计,所以可能只需提供连接示意图。 需要检查可能的错误点,例如波特率计算是否正确,中断是否使能,缓冲区是否足够大,防止溢出。此外,数据解析时的字符串处理是否高效,是否有内存泄漏的风险,特别是在频繁接收数据的情况下。 最后,测试代码是关键。需要验证串口是否能正确接收数据,解析后的经纬度和高度是否准确。可能使用模拟的GNGGA数据进行测试,逐步调试各部分功能。 现在,用户可能需要具体的代码示例和配置步骤。我需要确保代码符合STC8H8K64U的寄存器配置习惯,使用Keil C51语法。同时,原理图部分需要标注相关引脚和外围电路,确保用户能正确连接硬件。 可能遇到的问题包括:串口无法正确接收数据,可能是波特率配置错误;数据解析不完整,可能是缓冲区大小不足或中断处理不当;转换后的数值有误,可能是格式处理错误。需要在代码中添加注释,帮助用户理解各部分功能,并在解析函数中加入错误检查机制,如校验和验证。 总结步骤:配置串口2和4,设置中断接收,解析GNGGA语句,转换数据格式,输出结果。确保代码结构清晰,模块化,方便用户调整和扩展。</think>### STC8H8K64U串口通信与GNSS数据解析解决方案 #### 一、硬件架构设计 1. **串口配置** - **串口2**:使用P1.0(TXD2)和P1.1(RXD2) - **串口4**:使用P0.2(TXD4)和P0.3(RXD4) - **电平转换**:建议采用CH340C芯片实现USB-TTL转换[^1] 2. **北斗模块连接** ``` GNSS模块TXD -> 单片机RXD2(P1.1) 单片机TXD4(P0.2) -> PC调试终端 ``` #### 二、软件架构设计 1. **系统框图** ``` [GNSS模块] → 串口2 → 数据接收 → GNGGA解析 → 坐标转换 → 串口4输出 ``` #### 三、核心代码实现 ```c #include <STC8H.H> #include <string.h> #include <stdio.h> #define BUF_SIZE 128 xdata char uart2_buffer[BUF_SIZE]; volatile unsigned char uart2_cnt = 0; // 串口2初始化(GNSS输入) void UART2_Init(void) { S2CON = 0x50; // 8位数据,可变波特率 T2L = 0xFE; // 115200@24MHz T2H = 0xFF; // 定时器2时钟源设置 AUXR = 0x14; // 启动定时器2 IE2 |= 0x01; // 使能串口2中断 } // 串口4初始化(调试输出) void UART4_Init(void) { S4CON = 0x10; // 8位数据,可变波特率 T3L = 0xFE; // 115200@24MHz T3H = 0xFF; T4T3M = 0x0C; // 启动定时器3 IE2 |= 0x04; // 使能串口4中断 } // 串口2中断服务 void UART2_ISR() interrupt 8 { if(S2CON & 0x01){ S2CON &= ~0x01; uart2_buffer[uart2_cnt] = S2BUF; if(uart2_buffer[uart2_cnt] == '\n' || uart2_cnt >= BUF_SIZE-1){ uart2_buffer[uart2_cnt] = '\0'; Parse_GNGGA(uart2_buffer); uart2_cnt = 0; }else{ uart2_cnt++; } } } // GNGGA数据解析 void Parse_GNGGA(char *data) { char *p = strtok(data, ","); float latitude, longitude, altitude; if(strcmp(p, "$GNGGA") == 0){ // 时间字段 p = strtok(NULL, ","); // 纬度处理 p = strtok(NULL, ","); latitude = atof(p) / 100; p = strtok(NULL, ","); // 方向 if(*p == 'S') latitude = -latitude; // 经度处理 p = strtok(NULL, ","); longitude = atof(p) / 100; p = strtok(NULL, ","); // 方向 if(*p == 'W') longitude = -longitude; // 高度提取 for(int i=0; i<3; i++) p = strtok(NULL, ","); altitude = atof(p); // 通过串口4输出结果 printf("纬度:%.6f 经度:%.6f 高度:%.1fm\n", latitude, longitude, altitude); } } // 主函数 void main() { UART2_Init(); UART4_Init(); EA = 1; while(1); } ``` #### 四、关键配置说明 1. **波特率计算**: 使用定时器2/3的8位自动重载模式,计算公式: $$Baud = \frac{SYSclk}{4 \times (256 - TH1)}$$ 当系统时钟24MHz时,TH1=0xFF对应115200波特率[^2] 2. **数据格式转换**: - 纬度格式转换:`ddmm.mmmm → dd + mm.mmmm/60` - 经度格式转换:`dddmm.mmmm → ddd + mm.mmmm/60` #### 五、原理图要点 1. **最小系统**:包含复位电路、时钟电路(建议24MHz晶振) 2. **串口连接**: - P1.1接GNSS模块TXD - P0.2接USB-TTL芯片RXD 3. **供电设计**:建议采用AMS1117-3.3V为GNSS模块供电
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值