上位机图像处理和嵌入式模块部署(mcu 项目1:固件编写)

news2024/11/18 0:35:56

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

        说完了上位机的开发,接下来就是固件的开发。前面我们说过,目前使用的开发板是极海apm32f103的开发板。它自身包含了iap示例,里面既有bootloader的代码,也有app的代码。所以,我们需要做的就是在app的基础之上,添加自己需要的功能就可以了,bootloader就不用处理了。这也是大部分mcu模块的开发方式。

1、修改中断向量基地址和链接地址

        这部分代码如果不修改的话,我们需要每次通过bootloader来加载app的bin文件。这对于开发来说,不是很方便,所以这部分还是建议修改一下,等到最后部署的时候再改回来。其实,修改的地方就两处,

#define FLASH_APP1_ADDR 0x0000

        还有一处就是链接的地方,

2、添加新的串口

        之前我们使用了debug串口,可以写数据、读数据。实际上开发的时候需要两个串口,最好分开来。一个串口用于debug调试,一个用于和上位机之间的通信。现在是这么安排的,之前的debug串口,也就是pa9、pa10用于串口通信使用。这里重新添加一个usart3,用于调试使用,对应的pin脚是pb10、pb11,这部分可以通过厂家的芯片手册查找到。其中,头文件的定义如下所示,

#ifndef __USART3_H
#define __USART3_H

#include "./SYSTEM/sys/sys.h"
#include "apm32f10x_usart.h"
#include <stdio.h>


#define USART3_TX_GPIO_PORT          GPIOB
#define USART3_TX_GPIO_PIN           GPIO_PIN_10
#define USART3_TX_GPIO_CLK_ENABLE()  do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB); }while(0)     

#define USART3_RX_GPIO_PORT          GPIOB
#define USART3_RX_GPIO_PIN           GPIO_PIN_11
#define USART3_RX_GPIO_CLK_ENABLE()  do{ RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_GPIOB); }while(0)     

#define USART3_UX                    USART3
#define USART3_UX_IRQn               USART3_IRQn
#define USART3_UX_IRQHandler         USART3_IRQHandler
#define USART3_UX_CLK_ENABLE()       do{ RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_USART3); }while(0)    

void usart3_init(uint32_t baudrate);            
int sendChar(int ch);                            
void sendString(char* str);                      
void sendNumber(int num);                       

#endif

        具体的c实现代码如下所示,

#include "./SYSTEM/usart3/usart3.h"
#include "apm32f10x_rcm.h"
#include "apm32f10x_gpio.h"
#include "apm32f10x_misc.h"

void usart3_init(uint32_t baudrate)
{
    GPIO_Config_T gpio_init_struct = {0};
    USART_Config_T usart_init_struct = {0};
    
    USART3_UX_CLK_ENABLE();
    USART3_TX_GPIO_CLK_ENABLE();
    USART3_RX_GPIO_CLK_ENABLE();
    
    gpio_init_struct.pin = USART3_TX_GPIO_PIN;
    gpio_init_struct.speed = GPIO_SPEED_50MHz;
    gpio_init_struct.mode = GPIO_MODE_AF_PP;
    GPIO_Config(USART3_TX_GPIO_PORT, &gpio_init_struct);
    
    gpio_init_struct.pin = USART3_RX_GPIO_PIN;
    gpio_init_struct.speed = GPIO_SPEED_50MHz;
    gpio_init_struct.mode = GPIO_MODE_IN_PU;
    GPIO_Config(USART3_RX_GPIO_PORT, &gpio_init_struct);
    
    usart_init_struct.baudRate = baudrate;                    
    usart_init_struct.wordLength = USART_WORD_LEN_8B;         
    usart_init_struct.stopBits = USART_STOP_BIT_1;         
    usart_init_struct.parity = USART_PARITY_NONE;            
    usart_init_struct.mode = USART_MODE_TX_RX;              
    usart_init_struct.hardwareFlow = USART_HARDWARE_FLOW_NONE; 
    USART_Config(USART3_UX, &usart_init_struct);
    USART_Enable(USART3_UX);
}

int sendChar(int ch)
{
    while (USART3_UX->STS_B.TXCFLG == 0);    
	
    USART3_UX->DATA_B.DATA = (uint16_t)ch;   
    return ch;
}

void sendString(char* str)
{
		char* pStart = str;
	
		while(*pStart)
		{
			  sendChar(*pStart);
			  pStart++;
		}
}

static void _sendNumber(int num)
{
	    if(num > 9)
		{
	        sendNumber(num / 10);
		}
		
		num = num % 10;
		switch(num)
		{
			case 0:
				sendChar('0');
			    break;
			
			case 1:
				sendChar('1');
			    break;
			
			case 2:
				sendChar('2');
			  break;
			
			case 3:
				sendChar('3');
			    break;
			
			case 4:
				sendChar('4');
			    break;
			
			case 5:
				sendChar('5');
			    break;
			
			case 6:
				sendChar('6');
			    break;
			
			case 7:
				sendChar('7');
			    break;
			
			case 8:
				sendChar('8');
			    break;
			
			case 9:
				sendChar('9');
			    break;
			
			default:
				break;
		}
}

void sendNumber(int num)
{
	unsigned int val;
	if(num < 0)
	{
		sendChar('-');
        val = -num;
	}
	else
	{
		val = num;
	}
	
	_sendNumber(val);
}

        为了调试的方便,我们还实现了sendChar、sendString、sendNumber三个函数,到时候可以直接利用这几个打印函数调试即可。

3、添加内部flash读写代码

        因为涉及到参数的保存,所以势必涉及到内部flash的读写。这部分内容可以直接从对应的示例代码中copy即可,

uint16_t apmflash_read_halfword(uint32_t faddr);
void apmflash_read(uint32_t raddr, uint16_t *pbuf, uint16_t length); 
void apmflash_write_nocheck(uint32_t waddr, uint16_t *pbuf, uint16_t length);
void apmflash_write(uint32_t waddr, uint16_t *pbuf, uint32_t length);  
void test_write(uint32_t waddr, uint16_t data);                 

4、添加adc代码

        和内部flash读写一样,目前adc也有现成的case可以参考,所以相关代码直接copy即可,

void adc_init(void);
uint16_t adc_get_result(uint8_t ch); 
uint16_t adc_get_result_average(uint8_t ch, uint8_t times); 

5、确认之前的串口接收协议

        除了上面4点之外,还要确认下当前之前debug串口是否包含有接收功能,相关的逻辑是什么。通过仔细阅读代码,正好在中断处理里面发现了相关的逻辑,

void USART_UX_IRQHandler(void)
{
    if (USART_ReadIntFlag(USART_UX, USART_INT_RXBNE) == SET)
    {     
        g_rx_buffer[0] = USART_RxData(USART_UX);   
        
        if ((g_usart_rx_sta & 0x8000) == 0)      
        {
            if (g_usart_rx_sta & 0x4000)         
            {
                if (g_rx_buffer[0] != 0x0A)
                {
                    g_usart_rx_sta = 0;            
                }
                else
                {
                    g_usart_rx_sta |= 0x8000;      
                }
            }
            else                                   
            {
                if (g_rx_buffer[0] == 0x0D)
                {
                    g_usart_rx_sta |= 0x4000;
                }
                else
                {
                    g_usart_rx_buf[g_usart_rx_sta & 0x3FFF] = g_rx_buffer[0];
                    g_usart_rx_sta++;
                    if (g_usart_rx_sta > (USART_REC_LEN - 1))
                    {
                        g_usart_rx_sta = 0;       
                    }
                }
            }
        }
        
        USART_ClearIntFlag(USART_UX, USART_INT_RXBNE);
    }
}

6、gpio高低电平设定

        这部分之前的demo已经设定好,直接skip即可。

7、总结

        等我们想好要实现哪些功能的时候,其实做起来并不麻烦,关键是前面要规划好。还有一点,就是要善于复用厂家给出的demo代码,以及阅读厂家的芯片手册,这些第一手的资料不一定文档上能找到,只能自己通过文档阅读的方法一点、一点去挖掘,总是可以解决的。

        最后要提及的就是版本管理,非常推荐大家在本地用git把代码管起来。不管过分相信自己的记忆力,好记忆不如烂笔头。回到代码本身,就是好记忆不如git软件好使。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1884333.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

人工智能--目标检测

欢迎来到 Papicatch的博客 文章目录 &#x1f349;引言 &#x1f349;概述 &#x1f348;目标检测的主要流程通常包括以下几个步骤 &#x1f34d;数据采集 &#x1f34d;数据预处理 &#x1f34d;特征提取 &#x1f34d;目标定位 &#x1f34d;目标分类 &#x1f348;…

千益畅行,旅游卡,如何赚钱?

​ 赚钱这件事情&#xff0c;只有自己努力执行才会有结果。生活中没有幸运二字&#xff0c;每个光鲜亮丽的背后&#xff0c;都是不为人知的付出&#xff01; #旅游卡服务#

【分布式数据仓库Hive】Hive的安装配置及测试

目录 一、数据库MySQL安装 1. 检查操作系统是否有MySQL安装残留 2. 删除残留的MySQL安装&#xff08;使用yum&#xff09; 3. 安装MySQL依赖包、客户端和服务器 4. MySQL登录账户root设置密码&#xff0c;密码值自定义&#xff0c;这里是‘abc1234’ 5. 启动MySQL服务 6…

element plus 日期组件中英文切换

现在的项目需要做中英文切换功能&#xff0c;我发现element plus 只有日期组件不能转换&#xff0c;然后上网查了一下并结合自己的方法写了出来。 代码&#xff1a; <template><!-- 日期框组件 --><div class"time-box">//:locale"locale&qu…

嵌入式UI开发-lvgl+wsl2+vscode系列:5、事件(Events)

一、前言 这节进行事件的总结&#xff0c;通过事件回调方式将用户和ui的交互行为绑定组合起来。 二、事件示例 1、示例1&#xff08;点击事件&#xff09; #include "../lv_examples.h" #if LV_BUILD_EXAMPLES && LV_USE_SWITCHstatic void event_cb(lv_…

解锁机器学习算法面试挑战课程

在这个课程中&#xff0c;我们将从基础知识出发&#xff0c;系统学习机器学习与算法的核心概念和实践技巧。通过大量案例分析和LeetCode算法题解&#xff0c;帮助您深入理解各种面试问题&#xff0c;并掌握解题技巧和面试技巧。无论是百面挑战还是LeetCode算法题&#xff0c;都…

华为智能驾驶方案剖析

华为ADS智驾方案始终坚持激光雷达毫米波雷达摄像头的多传感器融合路线&#xff0c;行业降本压力下硬件配置从超配逐步转向贴合实际需求&#xff0c;带动整体硬件成本下降。 1)单车传感器数量呈现下降趋势&#xff0c;包括激光雷达从3个减配至1个、毫米波雷达从6R减配至3R、摄像…

firewalld防火墙概念(形态、分类、区域)相关综合示例

目录 防火墙 概念 形态 内核态&#xff1a;netfilter 用户态&#xff1a;iptables、firewalld 防火墙分类 firewalld网络区域 区域划分 使用图形化界面配置防火墙 端口配置 协议配置 源端口配置 永久配置恢复默认防火墙规则 配置防火墙相关命令 示例 实验环境 …

谷粒商城篇章10 -- P262-P291/P295-P310 -- 订单服务(支付)【分布式高级篇七】

目录 1 页面环境搭建 1.1 静态资源上传到nginx 1.2 SwitchHosts增加配置 1.3 网关配置 1.4 订单模块基础配置 1.4.1 引入 thymeleaf 依赖 1.4.2 application.yml配置 1.4.3 bootstrap.properties配置 1.4.4 开启nacos注册发现和远程调用 1.5 修改各个页面的静态资源路…

Hadoop权威指南-读书笔记-01-初识Hadoop

Hadoop权威指南-读书笔记 记录一下读这本书的时候觉得有意思或者重要的点~ 第一章—初识Hadoop Tips&#xff1a; 这个引例很有哲理嘻嘻&#x1f604;&#xff0c;道出了分布式的灵魂。 1.1 数据&#xff01;数据&#xff01; 这一小节主要介绍了进入大数据时代&#xff0c;面…

使用简鹿音频格式转换器轻松将MP3转换为WAV音频

在音频处理领域&#xff0c;不同的格式有其特定的应用场景。有时&#xff0c;我们可能需要将MP3格式的音频转换为WAV格式&#xff0c;以满足特定的播放或编辑需求。简鹿音频格式转换器就是一款能够帮助我们轻松实现这一转换目标的工具。 为什么选择 WAV 格式&#xff1f; WAV …

CentOS中使用SSH远程登录

CentOS中使用SSH远程登录 准备工作SSH概述SSH服务的安装与启动建立SSH连接SSH配置文件修改SSH默认端口SSH文件传输 准备工作 两台安装CentOS系统的虚拟机 客户机&#xff08;192.168.239.128&#xff09; 服务器&#xff08;192.168.239.129&#xff09; SSH概述 Secure S…

【RabbitMQ实战】Springboot 整合RabbitMQ组件,多种编码示例,带你实践 看完这一篇就够了

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、对RabbitMQ管理界面深入了解1、在这个界面里面我们可以做些什么&#xff1f; 二、编码练习&#xff08;1&#xff09;使用direct exchange(直连型交换机)&a…

【深圳大学算法设计与分析】 实验六 最大流应用问题 FF -> EK -> Dinic

目录 一、实验目的&#xff1a; 二、内容&#xff1a;棒球赛问题 三、实验要求 四、提交要求 ———————— 问题分析解释&#xff1a; ———————— 算法简解&#xff1a; Ford–Fulkerson 增广 Edmonds–Karp 算法 Dinic算法 Dinic和EK的区别&#xff1a; …

DDPM(Denoising Diffusion Probabilistic Models)

DDPM&#xff08;Denoising Diffusion Probabilistic Models&#xff09; 笔记来源&#xff1a; 1.Denoising Diffusion Probabilistic Models 2.大白话AI | 图像生成模型DDPM | 扩散模型 | 生成模型 | 概率扩散去噪生成模型 3.pytorch-stable-diffusion 扩散模型正向过程&am…

Kafka-服务端-网络层-源码流程

整体架构如下所示&#xff1a; responseQueue不在RequestChannel中&#xff0c;在Processor中&#xff0c;每个Processor内部有一个responseQueue 客户端发送的请求被Acceptor转发给Processor处理处理器将请求放到RequestChannel的requestQueue中KafkaRequestHandler取出reque…

易校网校园综合跑腿小程序源码修复运营版

简介&#xff1a; 易校网校园综合跑腿小程序源码修复运营版&#xff0c;带服务端客户端前端文档说明。 源码安装方法&#xff1a; 需要准备小程序服务号 服务器 备案域名 校园网跑腿小程序源码需要准备 1.小程序 2.服务器&#xff08;推荐配置2h4g3m&#xff09; 3.域名…

安卓实现微信聊天气泡

一搜没一个能用的&#xff0c;我来&#xff1a; 布局文件&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xml…

第十二章 路由器静态路由配置

实验目标 掌握静态路由的配置方法和技巧&#xff1b; 掌握通过静态路由方式实现网络的连通性&#xff1b; 熟悉广域网线缆的链接方式&#xff1b; 实验背景 学校有新旧两个校区&#xff0c; 每个校区是一个独立的局域网&#xff0c; 为了使新旧校区能够正常相互…

CTFHUB-SSRF-上传文件

通过file协议访问flag.php文件内容 ?urlfile:///var/www/html/flag.php 右键查看页面源代码&#xff0c;发现需要从内部上传一个文件这样才能正常获取到flag ?urlhttp://127.0.0.1/flag.php 发现无提交按钮&#xff0c;构造一个 <input type"submit" name&qu…