智能家居之主机--驱动层搭建

2023-05-16

智能家居之主机--驱动层搭建

  • bsp-底层驱动
    • bsp_gpio
    • bsp_adc
    • bsp_uart
    • bsp_timer
  • 伪调度

bsp-底层驱动

bsp_gpio

 利用一个config.h的配置文件,把所有要使用的gpio的属性配置好,这样有一个好处,比较集中,也比较好查,不需要一个文件一个文件去找,在config文件里面就把pin或者属性改掉了。首先定义一个结构体

typedef struct 
{
	uint32_t RCC_GPIOx	:32;
	uint16_t gpio_pin	:16;
	uint16_t gpio_mode  :8;
	uint16_t gpio_speed	:8;
}gpio_config_t;

(讲解:后面的:<num>是定义了一个num位的变量,但是只占用其中num位个内存,这样的好处是更加节省内存,名词叫位域)
一般刚入门的不太会去考虑在写代码的时候内存不够用的情况,要么就是全局变量满天飞,要么就是可能只需要存一个布尔型的参数的时候定义了一个占用32位内存的一个参数,如果是103c8t6这种内部flash并不大的芯片来说,如果代码量比较大的话肯定是不行的;可以来做个实验

#include<stdio.h>
#include<string.h>

typedef struct{
	unsigned int a : 4;
	unsigned int b : 1;
 } test_t;
 
typedef struct{
	unsigned int a;
	unsigned int b;
 } test1_t;

test_t test;
test1_t test1;
int main()
{
	test.a = 10;
	test.b = 1;
	test1.a = 10;
	test1.b = 1;
	printf("test_size:%d\r\n",sizeof(test));
	printf("test1_size:%d\r\n",sizeof(test1));
	return 0;
 } 

两个一样的结构体,一个限制位域一个不限制,运行一下看看这两个结构体占用内存的大小情况。

test_size:4
test1_size:8

画个图就好理解了
在这里插入图片描述
这个是test结构体的存放
在这里插入图片描述
这是test1的
所以回看上面gpio的结构体,如果不定义位域的话应该是占用10个字节,但是现在只占用了8个字节,可以通过keil的map来看一下内存使用情况。
在这里插入图片描述
然后就可以通过config的形式进行配置了

/******橘色LED的GPIO配置*******/
#define ORANGE_LED_GPIO_CONFIG		\
{									\
	RCC_APB2Periph_GPIOB,			\
	GPIO_Pin_9,						\
	GPIO_Mode_Out_OD,				\
	GPIO_Speed_50MHz, 		\
}

bsp_adc

 和bsp_gpio的定义方法相似,不过结构体更加复杂了一些,直接上代码;

typedef struct 
{
	uint32_t RCC_ADCx	:32;
	uint32_t adc_mode	:20;
	FunctionalState adc_scanconvmode  :1;
	FunctionalState adc_continuousconvmode	:1;
	uint32_t adc_externaltrigconv	:20;
	uint32_t adc_dataalign	:12;
	uint8_t  adc_nbrofchannel	:4;
	uint8_t Rank	:4; 
	uint8_t ADC_SampleTime	:4;
}adc_config_t;

那么相应的配置就是

/******MQ_2ADC*******/
#define MQ_2_ADC_CONFIG			\
{								\
	RCC_APB2Periph_ADC1,		\
	ADC_Mode_Independent,		\
	DISABLE,					\
	DISABLE,					\
	ADC_ExternalTrigConv_None,	\
	ADC_DataAlign_Right,		\
	1,							\
	1,							\
	ADC_SampleTime_239Cycles5,	\
}

再来看看map文件adc占用的内存字节数
在这里插入图片描述
那么bsp的ADC初始化函数就可以这样写

/**
 * 名称: BSP_ADC_Init
 * 功能:ADC初始化函数
 * 输入: 
 * @ADC_TypeDef: ADC序号
 * @adc_config_t: ADC相关配置
**/
void BSP_ADC_Init(ADC_TypeDef* ADCx,adc_config_t adc_config)
{
	ADC_InitTypeDef ADC_InitStructure;
	RCC_APB2PeriphClockCmd(adc_config.RCC_ADCx,ENABLE);
	
	ADC_DeInit(ADCx);
	
	ADC_InitStructure.ADC_Mode = adc_config.adc_mode;	
	ADC_InitStructure.ADC_ScanConvMode = adc_config.adc_scanconvmode;	
	ADC_InitStructure.ADC_ContinuousConvMode = adc_config.adc_continuousconvmode;	
	ADC_InitStructure.ADC_ExternalTrigConv = adc_config.adc_externaltrigconv;	
	ADC_InitStructure.ADC_DataAlign = adc_config.adc_dataalign;	
	ADC_InitStructure.ADC_NbrOfChannel = adc_config.adc_nbrofchannel;	
	ADC_Init(ADCx, &ADC_InitStructure);	 
  
	ADC_Cmd(ADCx, ENABLE);	
	
	ADC_ResetCalibration(ADCx);	
	 
	while(ADC_GetResetCalibrationStatus(ADCx));	
	
	ADC_StartCalibration(ADCx);	
 
	while(ADC_GetCalibrationStatus(ADCx));	 
}

后面定义初始化ADC的时候就不需要一大堆了,只需要调用这个函数把参数传进去即可。

bsp_uart

  串口结构体定义:

typedef struct
{
	uint32_t RCC_USARTx			:32;
	uint32_t bound 				:32;
	uint16_t wordlength 		:16;
	uint16_t stopbit			:16;
	uint16_t parity				:12;
	uint16_t hwflowcontrol		:12;
	uint16_t mode				:4; 
	uint8_t  irqchannel			:8; 
	uint8_t  irqpreemption		:8; 
	uint8_t	 irqSub				:8; 
}uart_config_t;
/**
 * 名称: BSP_UART_Init
 * 功能:串口初始化函数
 * 输入: 
 * @USART_TypeDef: 串口序号
 * @uart_config_t: 串口相关配置
**/
void BSP_UART_Init(USART_TypeDef* USARTx,uart_config_t uart_config)
{
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	if(USARTx == USART1)
		RCC_APB2PeriphClockCmd(uart_config.RCC_USARTx,ENABLE);
	else
		RCC_APB1PeriphClockCmd(uart_config.RCC_USARTx,ENABLE);
	
	USART_InitStructure.USART_BaudRate = uart_config.bound;
	USART_InitStructure.USART_WordLength = uart_config.wordlength;
	USART_InitStructure.USART_StopBits = uart_config.stopbit;
	USART_InitStructure.USART_Parity = uart_config.parity;
	USART_InitStructure.USART_HardwareFlowControl = uart_config.hwflowcontrol;
	USART_InitStructure.USART_Mode = uart_config.mode;	
	USART_Init(USARTx, &USART_InitStructure); 
	 
	USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);
	
	USART_Cmd(USARTx, ENABLE); 

	NVIC_InitStructure.NVIC_IRQChannel = uart_config.irqchannel;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=uart_config.irqpreemption;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority =uart_config.irqSub;		
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			
	NVIC_Init(&NVIC_InitStructure);	
}

注意由于串口1和串口2需要开的RCC时钟不同,底层直接区分开感觉会方便点;

bsp_timer

 同理直接上代码吧

typedef struct
{
	uint32_t period 		:16; //自动重装载值
	uint16_t Prescaler		:16; //定时器分频
	uint16_t countermode	:8;  //计数方式
	uint16_t clockdivision	:12; //时钟分割
	
	uint8_t irq_channel		:8;  //中断类型
	uint8_t irq_preemption	:8;  //抢占优先级
	uint8_t irq_subpriority :8;  //子优先级
	bool    enble_sta		:1;	 //是否使能定时器
}timer_config_t;
/**
 * 名称: BSP_TIME_Init
 * 功能:定时器初始化函数
 * 输入: 
 * @RCC_TIMx: 定时器时钟
 * @TIM_TypeDef: 定时器序号
 * @timer_config_t: 定时器相关配置
**/
void BSP_TIME_Init(uint32_t RCC_TIMx,TIM_TypeDef* TIMx,timer_config_t timer_config)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_TIMx,ENABLE);  
	
	TIM_TimeBaseInitStructure.TIM_Period = timer_config.period; 	
	TIM_TimeBaseInitStructure.TIM_Prescaler=timer_config.Prescaler;  
	TIM_TimeBaseInitStructure.TIM_CounterMode=timer_config.countermode; 
	TIM_TimeBaseInitStructure.TIM_ClockDivision=timer_config.clockdivision; 
	
	TIM_TimeBaseInit(TIMx,&TIM_TimeBaseInitStructure);
	
	TIM_ITConfig(TIMx,TIM_IT_Update,ENABLE); 
	 
	
	NVIC_InitStructure.NVIC_IRQChannel=timer_config.irq_channel; 
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=timer_config.irq_preemption; 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=timer_config.irq_subpriority; 
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIMx,timer_config.enble_sta);
}

伪调度

 定时器初始化后就可以开始搭建伪调度了,首先定义一个伪调度的结构体;

typedef struct
{
	void(*task_func)(void);
	uint16_t rate_hz;
	uint16_t interval_ticks;
	uint32_t last_run;
}sched_task_t;

将每个任务和轮询时间定义好后放入放入结构体中;

static sched_task_t sched_task[]=
{
	{loop_1ms,1000,0,0},
	{loop_10ms,100,0,0},
	{loop_100ms,10,0,0},
	{loop_1s,1,0,0},
};

我定义了这些时间段的任务,然后进行轮询任务的轮询结束时间进行计算;

void loop_check(void)
{
	u8 index = 0;
	for(index = 0;index <task_num;index++ )
	{
		sched_task[index].interval_ticks = 1000/sched_task[index].rate_hz;
		if(sched_task[index].interval_ticks < 1)
			sched_task[index].interval_ticks = 1;
	}
}

然后就可以开始轮询任务了,通过duty_loop函输,通过当前的时间和结束时间还有轮询时间进行对比,如果大于就执行对应函数;

void duty_loop(void)
{
	u8 index = 0;
	for(index = 0;index < task_num;index++)
	{
		uint32_t tnow = get_sys_time_ms();
		if(tnow - sched_task[index].last_run >= sched_task[index].interval_ticks)
		{
			sched_task[index].last_run = tnow;
			sched_task[index].task_func();
		}	
	}
}

然后我们就可以在loop_1s函数里面加入一个LED亮灭的函数,不需要使用delay函数看看是否能够1s切换。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

智能家居之主机--驱动层搭建 的相关文章

  • C++文件服务器项目—FastDFS—1

    C 43 43 文件服务器项目 FastDFS 1 前言1 项目架构2 分布式文件系统2 1 传统文件系统2 2 分布式文件系统 3 FastDFS介绍3 1 fdfs概述3 2 fdfs框架中的三个角色3 3 fdfs三个角色之间的关系3
  • C++文件服务器项目—Redis—2

    C 43 43 文件服务器项目 Redis 2 前言1 数据库类型1 1 基本概念1 2 关系 非关系型数据库搭配使用 2 redis基础知识点2 1 redis安装2 2 redis中的两个角色2 3 redis中数据的组织格式2 4 r
  • C++文件服务器项目—Nginx—3

    C 43 43 文件服务器项目 Nginx 3 前言1 Nginx一些基本概念1 1 Nginx初步认识1 2 正向代理概念理解1 3 反向代理概念理解 2 Nginx的安装与配置2 1 Nginx与相关依赖库的安装2 2 Nginx相关的
  • C++文件服务器项目—FastCGI—4

    C 43 43 文件服务器项目 FastCGI 4 前言1 CGI 概念理解2 FastCGI 概念理解3 FastCGI和spawn fcgi安装4 FastCGI和 Nginx的关系5 Nginx数据转发 修改配置文件6 spawn f
  • C++文件服务器项目—Nginx+FastDFS插件—5

    C 43 43 文件服务器项目 Nginx 43 FastDFS插件 5 前言1 文件上传下载流程1 1 文件上传流程1 2 文件下载流程1 3 文件下载优化流程 2 Nginx和fastDFS插件2 1 安装Nginx和fastdfs n
  • C++文件服务器项目—数据库表设计 与 后端接口设计—6

    C 43 43 文件服务器项目 数据库表的设计 6 前言1 数据库建表1 1 用户信息表 user info1 2 文件信息表 file info1 3 用户文件列表表 user file list1 4 用户文件数量表 user file
  • C语言中宏定义的使用

    1 引言 预处理命令可以改变程序设计环境 提高编程效率 它们并不是 C 语言本身的组成部分 不能直接对 它们进行编译 必须在对程序进行编译之前 先对程序中这些特殊的命令进行 预处理 经过预处理后 程序就不再包括预处理命令了 最后再由编译程序
  • C++文件服务器项目—项目总结与反向代理—7

    C 43 43 文件服务器项目 项目总结与反向代理 7 1 项目总结2 项目提炼3 web服务器的反向代理4 存储节点的反向代理 组件介绍基本写完了 xff0c 后续进行深入 本专栏知识点是通过零声教育的线上课学习 xff0c 进行梳理总结
  • https相关内容

    https相关内容 前言基础概念理解https传输过程 前言 本文写https相关内容 xff0c 持续补充 基础概念理解 对称加密 加解密秘钥是同一个 非对称加密 公钥 私钥 sa gt 公钥私钥都是两个数字ecc gt 椭圆曲线 两个点
  • TinyKv介绍

    TinyKv介绍 前言tinykv架构代码结构如何去写TinyKv参考内容 前言 开一个新坑 xff0c 将tinykv的4个project全部实现 虽然今天我点进去看的时候就萌生退意 好在没有放弃之前 xff0c 把project1完成了
  • TinyKv Project1 Standalone KV

    TinyKv Project1 Standalone KV 前言Project1 StandaloneKV 文档翻译文档的重点内容StandAloneStorageWriteReader Server单元测试 前言 project1还是比较
  • TinyKv Project2 PartA RaftKV

    TinyKv Project2a RaftKV 前言Project2 RaftKV 文档翻译Project2A重点内容抛出RaftLogRaftLog结构体字段详解RaftLog核心函数详解 RaftRaft 驱动规则Msg的作用与含义Ms
  • TinyKv Project2 PartB RaftKV

    TinyKv Project2 PartB RaftKV 前言Project2 PartB RaftKV 文档翻译PartB 到底想让我们做什么 xff1f 分析要实现的函数到底要干什么事情proposeRaftCommand 将上层命令打
  • TinyKv Project2 PartC RaftKV

    TinyKv Project2 PartC RaftKV 前言Project2 PartC RaftKV 文档翻译raft节点如何自动的compact压缩自己的entries日志生成快照与快照收收发日志压缩与快照收发总结疑难杂症 前言 pr
  • TinyKv Project3 PartA Multi-raft KV

    TinyKv Project3 PartA Multi raft KV 前言Project3 PartA Multi raft KV 文档翻译Add RemoveLeaderTransfer 前言 Project3是整个项目最难的部分 xf
  • TinyKv Project3 PartB Multi-raft KV

    TinyKv Project3 PartB Multi raft KV 前言Project3 PartB Multi raft KV 文档翻译发送请求LeaderTransfer 禅让ConfChange 集群成员变更Split regio
  • TinyKv Project3 PartC Multi-raft KV

    TinyKv Project3 PartC Multi raft KV 前言Project3 PartC Multi raft KV 文档翻译processRegionHeartbeatSchedule 前言 3C要求我们实现调度 3c按照
  • nodejs api学习:fs.createReadStreame()

    作用 这个api的作用是打开一个可读的文件流并且返回一个fs ReadStream对象 参数 createReadStream path option 该用来打开一个可读的文件流 xff0c 它返回一个fs ReadStream对象 64

随机推荐

  • TinyKv Project4 Transactions

    TinyKv Project4 Transactions 前言Project4 Transactions 文档翻译Project 4 TransactionsTinyKV中的事务Part APart BPart C Percolator x
  • sealos issue #2157 debug 思路流程记录

    sealos issues 2157 debug思路流程 前言分析issue剖析源码解决方案总结 前言 这个项目蛮有意思的 xff0c sealos 是以 kubernetes 为内核的云操作系统发行版 boss上看到 gt 沟通 gt 解
  • 系统设计场景题—MySQL使用InnoDB,通过二级索引查第K大的数,时间复杂度是多少?

    系统设计场景题 MySQL使用InnoDB xff0c 通过二级索引查第K大的数 xff0c 时间复杂度是多少 xff1f 前言明确场景对齐表的结构分析时间复杂度执行一条 select 语句 xff0c 期间发生了什么 xff1f 分析性能
  • 《嵌入式系统》 |(四) STM32软件架构 知识梳理

    系列索引 嵌入式系统 嵌入式系统 重点知识梳理 目录 CMSIS软件架构库文件说明 CMSIS软件架构 CMSIS概述 CMSIS软件架构由四层 xff1a 用户应用层 操作系统及中间件接口层 CMSIS层和硬件层 由三部分构成 核内外设访
  • Cmake链接第三方库的三种方法

    Cmake链接第三方库的三种方法 本文介绍链接第三方库的3种方法 以OpenBLAS举例 使用的工程名称为Test lib xff08 可执行文件名字 xff09 xff0c 主程序为library c 代码中的各路径请自行替代 xff1a
  • SADP功能使用

    SADP主要使用的是链路层多播及UDP多播的原理进行实现的 1 链路层多播 span class token function socket span span class token punctuation span PF PACKET
  • MatlabR2022b + Visual Studio环境配置

    在Matlab中输入 mex setup c 43 43 命令确认MEX使用VS2022编译环境 VC 43 43 目录 包含目录 添加 D Matlab2022b extern include VC 43 43 目录 库目录 添加 D M
  • ROS小车自主导航

    在进行ROS小车自主导航时 xff0c 需要用到三维可视化软件rviz xff0c 然而出现了问题 问题 xff1a 在运行rosrun rviz rviz xff0c 导入自己导航的程序后 xff0c 需要通过2D Pose Estima
  • SIYI AK28 遥控器接收机的SBUS口与STM32通讯

    SBUS介绍 SBUS是Futaba公司定义的一种串口通信协议 xff0c Futaba的产品应用越来越广泛 xff0c 不论是航模 xff0c 无人机 xff0c 还是机器人 xff0c 遥控车 xff0c 总能有它的身影 SBUS是一个
  • 基于STM32F407四旋翼无人机---AK8975磁力计(四)

    基于STM32F407四旋翼无人机 AK8975磁力计 xff08 四 xff09 磁力计基本介绍1 2 磁力计原理图 2 磁力计数据获取3 磁力计椭球拟合校准3 1 简单介绍椭球拟合 磁力计基本介绍 该模块采用高灵敏度霍尔传感器技术 xf
  • 硬链接与软链接

    硬链接 hard link 与软链接 xff08 又称符号链接 xff0c 即 soft link 或 symbolic link xff09 链接为 Linux 系统解决了文件的共享使用 xff0c 还带来了隐藏文件路径 增加权限安全及节
  • 基于STM32F407四旋翼无人机 --- 姿态解算讲解(四元数)(叉积法融合陀螺仪数据和加速度数据)(五)

    基于STM32F407四旋翼无人机 姿态解算讲解 xff08 五 xff09 姿态解算姿态解算定义欧拉角四元数四元数性质 方向余弦矩阵四元数方向余弦矩阵 叉积法融合陀螺仪数据和加速度数据叉积运算 一阶龙格库塔法四元数更新获得欧拉角 姿态解算
  • 基于STM32F407四旋翼无人机---PID算法控制(六)

    基于STM32F407四旋翼无人机 PID算法控制 xff08 六 xff09 PID介绍PID仿真分析 PID介绍 PID介绍 此算法是由P xff08 比例 xff09 I xff08 积分 xff09 和D xff08 微分 xff0
  • 四足机器人(一)----MATLAB simulink对四足机器人物理建模

    四足机器人 xff08 一 xff09 MATLAB simulink对四足机器人物理建模 一 本设计中用的是网上下载的别人已经画好的四足机器狗的3D模型 那么我们就需要将这些3D模型导入到MATLAB的建模中 xff0c 打开MATLAB
  • 四足机器人(二)---运动学逆解和步态规划

    四足机器人 xff08 二 xff09 运动学逆解和步态规划 运动学逆解步态规划MATLAB仿真 运动学逆解 其实运动学分为运动学正解和运动学逆解 xff0c 二者有什么区别呢 xff1f 因为在四足机器人中用的是12个舵机 xff0c 所
  • 四足机器人(三)--- 姿态控制

    四足机器人 xff08 三 xff09 姿态控制 概述姿态表示使用MATLAB实现姿态控制算法效果 概述 四足机器人运动过程中 xff0c 身体部分的姿态会不断地发生变化 假如机器人的足端一直保持与地面接触且相对位置不发生变化 xff0c
  • VSCode+python+opencv搭建过程

    VSCode 43 python 43 opencv搭建过程 python安装VSCode安装安装opencv python安装 首先打开python的官网 www python org xff0c 进入python官网下载页面 xff0c
  • 智能家居之主机---计划筹备

    智能家居之主机 计划筹备 前言绪言前期构思 硬件平台结构平台 前言 绪言 感觉有一年多没发过文章了 xff0c 这一年多太忙了 xff0c 来到新的公司后要学的太多了 xff0c 代码风格 xff0c 架构 xff0c 操作系统 xff0c
  • 智能家居之主机--环境搭建

    智能家居之主机 环境搭建 硬件环境软件环境结构 硬件环境 上节说到硬件平台的搭建 xff0c 之前是在altium designer上面画好的 xff0c 现在要支持国产 xff0c 没办法只能在立创EDA上面重新画了 xff0c 有的人说
  • 智能家居之主机--驱动层搭建

    智能家居之主机 驱动层搭建 bsp 底层驱动bsp gpiobsp adcbsp uartbsp timer 伪调度 bsp 底层驱动 bsp gpio 利用一个config h的配置文件 xff0c 把所有要使用的gpio的属性配置好 x