既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
让我们看看这个经典的图,简单了解一下框架分层。
从图中不难观察出,设计都是遵循设计的原则的,层与层之间不能相互调用。
二、框架分层的优劣势
1.优势
- 单一职责:每一层只负责一个职责,职责边界清晰,不会造成跨级调用,在大型项目中,每个人负责的部分不一样,加快整个项目的开发进度。
- 高内聚:分层是把相同的职责放在同一个层中,所有业务逻辑内聚在领域层。在测试的时候,只需要测试该领域的层即可,一般不需要考虑其他层的问题。
- 低耦合:依赖关系非常简单,上层只能依赖于下层,没有循环依赖。
- 易维护:面对变更容易修改。在平台更改后,如果只是改了驱动,其他层都不需要动,只需要把驱动层给更改,其他层的功能不需要更改。
- 易复用:如果功能模块变动了,只需升级相应的功能模块,其他的模块不受影响,应用层也不受影响。
如果想要更好地利用这些优势,那得严格遵循设计的原则。
2.劣势
- 开发成本高:因为多层分别承担各自的职责,增加功能需要在多个层增加代码,这样难免会增加开发成本。但是合理的抽象,根据自己的项目设置合理的层级是能降低开发成本的。
- 性能略低:业务流需要经过多层代码的处理,性能会有所消耗。
- 可扩展性低:因为上下层之间存在耦合度,有些功能变化可能涉及到多层的修改。
有优势也有劣势,需要根据自己的项目需要,进行部分的取舍,如果是中小型项目,可以不需要分层(如果不考虑到以后会迭代的话),或者部分分层就够了,既能利用框架分层的部分优势,也能降低开发成本。
三、一个简单的例子
由于主要讨论的是软件框架的分层设计,这里使用STM32cubemx来进行硬件的初始化,尽可能少考虑到硬件驱动的部分。
以一个智能小灯的作为例子:
功能
- 按键控制小灯的亮度,等级为:0,1,2,3
- 串口可以观察当前小灯亮度等级
- OLED也可以观察当前小灯亮度等级
下面就是这个例子的一个简单的图示。
这和例子比较简单,业务逻辑层完全可以去除,直接从应用层调用功能模块层,加快开发进度。
最后附上一点点代码,就是关于LED如何进行在不同层进行封装
硬件层
首先看HAL库生成提供的代码,这个就是LED
硬件层,也就是GPIO层,cubemx已经生成了,在stm32f4xx_hal_gpio.c(我用的是F4),以及有相应的GPIO的驱动了,这里不需要我们进行处理。
硬件层驱动层
看LED部分的驱动:
也就是下面的这两个函数
void MX\_TIM1\_Init(void);
void HAL\_TIM\_MspPostInit(TIM_HandleTypeDef\* timHandle);
/\* TIM1 init function \*/
void MX\_TIM1\_Init(void)
{
/\* USER CODE BEGIN TIM1\_Init 0 \*/
/\* USER CODE END TIM1\_Init 0 \*/
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/\* USER CODE BEGIN TIM1\_Init 1 \*/
/\* USER CODE END TIM1\_Init 1 \*/
htim1.Instance = TIM1;
htim1.Init.Prescaler = 168-1;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 10000;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL\_TIM\_Base\_Init(&htim1) != HAL_OK)
{
Error\_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL\_TIM\_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error\_Handler();
}
if (HAL\_TIM\_PWM\_Init(&htim1) != HAL_OK)
{
Error\_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL\_TIMEx\_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error\_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL\_TIM\_PWM\_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error\_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
if (HAL\_TIMEx\_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
{
Error\_Handler();
}
/\* USER CODE BEGIN TIM1\_Init 2 \*/
/\* USER CODE END TIM1\_Init 2 \*/
HAL\_TIM\_MspPostInit(&htim1);
}
void HAL\_TIM\_MspPostInit(TIM_HandleTypeDef\* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM1)
{
/\* USER CODE BEGIN TIM1\_MspPostInit 0 \*/
/\* USER CODE END TIM1\_MspPostInit 0 \*/
\_\_HAL\_RCC\_GPIOE\_CLK\_ENABLE();
/\*\*TIM1 GPIO Configuration
PE11 ------> TIM1\_CH2
\*/
GPIO_InitStruct.Pin = GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;
HAL\_GPIO\_Init(GPIOE, &GPIO_InitStruct);
/\* USER CODE BEGIN TIM1\_MspPostInit 1 \*/
/\* USER CODE END TIM1\_MspPostInit 1 \*/
}
}
对其进行封装,就是我们想要的Led小灯的驱动了,到时候如果需要,改驱动直接改底层就行了。
void Led\_init()
{
MX\_TIM1\_Init();
HAL\_TIM\_PWM\_Start(&htim1,TIM_CHANNEL_2);//启动PWM
}
功能模块层
根据上面的需求要求划分为四个不同等级,同时也需要对LED驱动进行进一步封装,以便满足层与层之间不能跨级调用的原则(到这里是不是发现很麻烦!小项目就不要用啦!)
//ARR计数器设置值为0~10000
#define LED\_GRADE\_0 0
#define LED\_GRADE\_1 3000
#define LED\_GRADE\_2 6000
#define LED\_GRADE\_3 10000
//设置LED亮度功能
void Led\_Set\_brightness(int Grade)
{
if(Grade==LED_GRADE_0)
{
\_\_HAL\_TIM\_SET\_COMPARE(&htim1, TIM_CHANNEL_2, Grade);
HAL\_TIM\_PWM\_Stop(&htim1,TIM_CHANNEL_2);//关闭PWM输出
}
else
{
HAL\_TIM\_PWM\_Start(&htim1, TIM_CHANNEL_2, Grade);
\_\_HAL\_TIM\_SET\_COMPARE(&htim1, TIM_CHANNEL_2, Grade);
}
![img](https://img-blog.csdnimg.cn/img_convert/bb0cab94a364424e9ec9f53725c9ee3c.png)
![img](https://img-blog.csdnimg.cn/img_convert/8827ecab9f53d4388f3710ec2d6aad18.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**
年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**