当前位置: 主页 > 建站知识 > 软件开发

嵌入式软件开发要求-可以嵌入字幕的软件

发布时间:2023-01-26 14:20   浏览次数:次   作者:佚名

我是老温,一名热爱学习的嵌入式工程师
关注我,一起变得更加优秀!

前言

为了在未来能够实现更好的产品开发速度和更好的迭代移植,框架分层是很有必要的。 但是,对于中小型项目,如果严格遵循这些原则,势必会消耗过多的精力去思考如何设计系统。 这是一个选择的过程。

1、什么是框架分层?

在嵌入式架构中:一般分为硬件架构和软件架构。 这就是嵌入式软件设计,也是大多数人接触的东西。

所谓分层也可以理解为模块化设计,但是框架分层的设计一般遵循以下原则

一般可分为:硬件驱动层->功能模块层->应用接口层->业务逻辑层->应用层

下面我们通过这张经典图来简单了解下框架分层。

c#软件嵌入谷歌地图_嵌入式软件开发要求_可以嵌入字幕的软件

从图中不难看出,设计遵循设计原则,层之间不能互相调用。

二、框架分层的优缺点 1、优点

要想更好地利用这些优势嵌入式软件开发要求,就必须严格遵循设计原则。

2.缺点

有优点也有缺点。 你需要根据自己的项目需求做一些取舍。 如果是中小型项目,可以不用分层(如果不考虑以后的迭代),或者一些层就够了。 您可以使用框架分层的部分优势还可以降低开发成本。

3.一个简单的例子

由于主要讨论的是软件框架的分层设计,这里使用STM32cubemx来初始化硬件,硬件驱动尽量少考虑。

以智能灯为例:

特征

下面是这个例子的简单说明。

这个例子比较简单,可以完全去掉业务逻辑层,直接从应用层调用功能模块层,加快开发进度。

可以嵌入字幕的软件_c#软件嵌入谷歌地图_嵌入式软件开发要求

最后附上一小段代码,是关于LED如何分层封装的。

硬件层

先看HAL库生成的代码。 这是LED硬件层,也就是GPIO层。 Cubemx 已经生成。 在stm32f4xx_hal_gpio.c(我用的是F4)里面,有对应的GPIO驱动。 我们这里不需要我们。 处理。

可以嵌入字幕的软件_嵌入式软件开发要求_c#软件嵌入谷歌地图

硬件层驱动层

再看LED部分的驱动,也就是下面两个函数

void MX_TIM1_Init(void);
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle);
12
/* 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 */
  }

}
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798

封装起来就是我们要的LED灯的驱动。 如果需要的话嵌入式软件开发要求,换个驱动就可以了,直接改底层。

void Led_init()
{
 MX_TIM1_Init();
 HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);//启动PWM
}
12345

功能模块层

根据以上要求,分为四个不同的等级。 同时,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);
 }
}

//启动LED功能
void Led_Start()
{
 Led_init();
}
12345678910111213141516171819202122232425

业务逻辑层

这里仅以启动层为例:

void Start_app()
{
 Led_Start();
}
1234

应用层

基本流程是:启动业务逻辑->读取业务逻辑->处理业务逻辑->显示业务逻辑。

四。 概括

至此,已经解释了一个简单的例子。 通过LED这个简单的例子,大致了解了这个设计的复杂性。 如果是大型项目,用起来会很爽。 小的话就没必要这么分层了,太麻烦了,严重拖慢开发效率,时间都花在想怎么分层才能符合框架分层的原则上了。

原始来源: