嵌入式Linux学习笔记

news/2024/9/18 12:50:58/ 标签: 单片机, 嵌入式Linux, 操作系统

1.文件操作命令


 

2.VI编辑器的部分命令
 


 

3.Uboot命令设置环境变量

4. uboot 的顶层 Makefile的重点是“make xxx_defconfig”和“make”这两个命令 ,分别如下:
 


 


 

5.在串口SecureCRT中利用uboot启动Linux内核的两种方式

6.Linux内核移植到开发板上也可以反过来想:即为向Linux内核文件中添加自己型号对应的开发板(自己型号的芯片)---(具体即为添加zImage:Linux镜像文件和.dtb:设备树文件)

7.反向不归零编码NRZI与位填充:

8.串口基本概念

全双工

低位先行

TXD发、RXD接

起始位 | 数据位 | 校验位 | 停止位

0 8-9位 奇/偶校验 1

通讯前的约定(协议)用串口时双方要协定好没传输一个数据需要多少秒(约定好波特率)

奇偶校验位

数据位+校验位个数位奇数个,则正确

波特率bps,每一秒传输数据的位数

传输:

可以直接连接一个模块

也可以连接一个电平转换芯片把TTL电平转换为RS485或者RS232

9.串口的三种编程方式

注意:中断方式和DMA方式

第一个Transmit都是使能中断,然后在中断中完成传输,在中断的最后有一个回调函数callback,callback为_weak函数,用户可以自己去写具体要求

1、查询方式

收/发数据时需要不停查看相应寄存器是否为空

2、中断方式

Transmit_IT使能中断

callback会给反馈,但也是会经常打断cpu

3、DMA

使用中断方式时,在传输、接收数据时,会发生中断,还需要 CPU 执行中断处理函数。有另外一种方法: DMA(Direct Memory Access),它可以直接在 2 个设备之间传递数据,无需 CPU 参与

DMA就是跑腿的

uart编程

查询方式不常用、其他两个方式用的多

三种方式,只实现串口2发送、串口4接收;

串口2接收、4发送省去;

中断方式:

收到一个字符就会产生一个中断,就会去中断cpu;DMA是接收完所有字符才产生一次中断

具体实现:

首先要使能中断

代码
static volatile int g_uart2_tx_complete = 0;//用来判断是否完成
static volatile int g_uart4_rx_complete = 0;void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{//数据返送完毕,中断函数会调用这个回调函数if(huart == &huart2){g_uart2_tx_complete = 1;//数据发送完后就会置成1,wait看到1则置为0表示完成、如果一直是0直到超时则返回-1表示失败}
}int Wait_UART2_Tx_Complete(int timeout)
{while(g_uart2_tx_complete == 0 && timeout){vTaskDelay(1);timeout--;};if(timeout == 0)//超时return -1;else{g_uart2_tx_complete = 0;return 0;}
}void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{//数据返送完毕,中断函数会调用这个回调函数if(huart == &huart4){g_uart4_rx_complete = 1;//数据发送完后就会置成1,wait看到1则置为0表示完成、如果一直是0直到超时则返回-1表示失败}
}int Wait_UART4_Rx_Complete(int timeout)
{while(g_uart4_rx_complete == 0 && timeout){vTaskDelay(1);timeout--;}if(timeout == 0)//超时return -1;else{g_uart4_rx_complete = 0;return 0;}
}
extern UART_HandleTypeDef huart4;
extern UART_HandleTypeDef huart2;//发送
int Wait_UART2_Tx_Complete(int timeout);
//接收
int Wait_UART4_Rx_Complete(int timeout);/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {.name = "defaultTask",.priority = (osPriority_t) osPriorityNormal,.stack_size = 128 * 4
};/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes *///任务函数
static void SPILCDTaskFunction( void *pvParameters )
{char bur[100];int cnt = 0;while(1){sprintf(bur, "lcd task test:%d" ,cnt++);//Draw_String(0, 0 , bur, 0x0000ff00, 0);vTaskDelay(1000);}}static void CH1_URAT2_TxTaskFunction( void *pvParameters )
{uint8_t c = 0;while(1){//发数据HAL_UART_Transmit_IT(&huart2, &c, 1);Wait_UART2_Tx_Complete(100);//等待发送完成vTaskDelay(500);c++;}
}static void CH2_URAT4_RxTaskFunction( void *pvParameters )
{uint8_t c = 0;char bur[100];int cnt = 0;HAL_StatusTypeDef err;while(1){//接收数据err = HAL_UART_Receive_IT(&huart4, &c, 1);//串口、内容地坿、长度㿁超旿if(Wait_UART4_Rx_Complete(10) == 0)//=0表示接收完成{sprintf(bur,"receive dataset : 0x:%02x, numember:%d",c, cnt++);Draw_String(0, 0, bur, 0x0000ff00, 0);}else{HAL_UART_AbortReceive_IT(&huart4);//超时或者出错则调用终止中断接收的函数}}}

原理

DMA方式:

在dma传输过程中不产生中断,传输完指定数量的数据后产生中断;

dma只会去中断cpu一次;

优点:DMA优势就在于可以接收很多数据;

源 | 目的 | 长度

发送:内存的源地址++、TDR

接收:RDR 、目的地址++

配置DMA

原理

代码

就只是把中断的代码的这些换了

效率最高的UART编程方式:
是什么?

正常的三种编程方式1启动2等待完成,一般是等到如下图设置的1000个字节都收到后停止,但是其他比如完整的数据收到了没到1000字节,以及长时间未响应、产生error就要用到IDLE中断;

等待完成如果已经收到完整的数据但是没有达到如下如1000个字节,那么就要靠IDLE中断来告知收到完整数据了。

问题:中断和DMA每次都要手工使能中断/启动DMA,如果代码里面有其他长时间的任务没结束,第二次就要等这个任务结束后才启动下一次;

方法:一开始就启动DMA

使用DAM+IDLE中断:

其他方式都可以用IDLE但是DMA是最好的,中断方式没有必要用这个,因为他要及时的获取数字每读到一个字节、就产生一次中断,去中断一次cpu

空闲而停止mcu检测到长的停止时间,就会产生IDLE中断

操作

1、一开始就使能IDLE的这个函数

2、实现回调函数

回调函数创建队列都是在中断函数中实现的,回调函数就是在中断函数中调用的

中断里面写队列要有一个后缀FromISR

在freertos里面调用uart

多了freertos队列

应该怎么做?

代码
static volatile int g_uart2_tx_complete = 0;//用来判断是否完成
static volatile int g_uart4_rx_complete = 0;
static uint8_t g_uart4_rx_buf[100];//定义一个buff来存接收到的数据
static QueueHandle_t g_xUART4_RX_Queue;//创建队列void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{//数据返鿁完毕,中断函数会调用这个回调函敿if(huart == &huart2){g_uart2_tx_complete = 1;//数据发鿁完后就会置房1,wait看到1则置丿0表示完成、如果一直是0直到超时则返囿-1表示失败}
}int Wait_UART2_Tx_Complete(int timeout)
{while(g_uart2_tx_complete == 0 && timeout){vTaskDelay(1);timeout--;};if(timeout == 0)//超时return -1;else{g_uart2_tx_complete = 0;return 0;}
}//接收完毕
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{//数据返鿁完毕,中断函数会调用这个回调函敿if(huart == &huart4){g_uart4_rx_complete = 1;//数据发鿁完后就会置房1,wait看到1则置丿0表示完成、如果一直是0直到超时则返囿-1表示失败//收到数据后把收到的数据存入buff,写队列for(int i = 0 ; i < 100; i++){xQueueSendFromISR(g_xUART4_RX_Queue,&g_uart4_rx_buf[i], NULL);}//重新启动DMA+IDLEHAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}
}//void event,接收空闲,表示数据已经接收完成,但是还没到DMA接收设置的值
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart == &huart4){g_uart4_rx_complete = 1;//写队列for(int i = 0 ; i < Size; i++){xQueueSendFromISR(g_xUART4_RX_Queue,&g_uart4_rx_buf[i], NULL);}//重新启动DMA+IDLEHAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}}//void error:重新启动DMA+IDLE
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{//重启DMA+IDLEHAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);
}int Wait_UART4_Rx_Complete(int timeout)
{while(g_uart4_rx_complete == 0 && timeout){vTaskDelay(1);timeout--;}if(timeout == 0)//超时return -1;else{g_uart4_rx_complete = 0;return 0;}
}//读数据,app从队列中读数据不从串口读数据了int UART4_GetData(uint8_t *pData)
{xQueueReceive(g_xUART4_RX_Queue,pData, portMAX_DELAY);return 0;
}void UART4_RX_Start(void)
{//开始前把上面定义好的队列创建处来g_xUART4_RX_Queue = xQueueCreate( 200, 1 );//启动接收HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);//收到的数据保存在哪里,要定义一个buff;收到后回调函数就会被调用
}
extern UART_HandleTypeDef huart4;
extern UART_HandleTypeDef huart2;
void UART4_RX_Start(void);
int UART4_GetData(uint8_t *pData);//发鿿
int Wait_UART2_Tx_Complete(int timeout);
//接收
int Wait_UART4_Rx_Complete(int timeout);/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {.name = "defaultTask",.priority = (osPriority_t) osPriorityNormal,.stack_size = 128 * 4
};/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes *///任务函数
static void SPILCDTaskFunction( void *pvParameters )
{char bur[100];int cnt = 0;while(1){sprintf(bur, "lcd task test:%d" ,cnt++);//Draw_String(0, 0 , bur, 0x0000ff00, 0);vTaskDelay(1000);}}static void CH1_URAT2_TxTaskFunction( void *pvParameters )
{uint8_t c = 0;while(1){//发数捿HAL_UART_Transmit_DMA(&huart2, &c, 1);Wait_UART2_Tx_Complete(100);//等待发鿁完房vTaskDelay(500);c++;}
}static void CH2_URAT4_RxTaskFunction( void *pvParameters )
{uint8_t c = 0;char bur[100];int cnt = 0;HAL_StatusTypeDef err;while(1){//一开头就调用这个函数来调用到IDLEUART4_RX_Start();err = UART4_GetData(&c);//读到的数据保存在cif(err == 0)//=0表示接收完成{sprintf(bur,"receive dataset : 0x:%02x, numember:%d",c, cnt++);Draw_String(0, 0, bur, 0x0000ff00, 0);}else{HAL_UART_DMAStop(&huart4);//超时或迅出错则调用终止中断接收的函敿}}}

200个数据,每个数据一个字节

面向对象封装UART

构造处结构体,包含uart里面的初始话函数、构造函数等等;

串口的DMA设置:

前面只设置了uart2发送和uart4接收;

现在设置uart4接收和uart2发送;

源地址叠加和目的地址是否叠加在前面写了;

发送一定是内存到外设,接收则相反

编写代码:

uart接收复制uart4接收,等待、获取数据、启动函数(等待接收函数不需要了删除即可,直接等待队列完成);

callback直接在callback里面复制;

getData设置超时时间;

等待函数去掉,等待队列就行了,换成freertos的信号量:

中断里面不能give互斥量mutex,啥是互斥量?信号量和互斥量

优先级的恢复工作不太好做

信号量:启动DAM、等待信号量、释放信号量(在回调函数)

过程原理

二进制信号量先定义出来->调用创建信号量函数

send函数发送出去,然后等待中断里面的callback回调函数give,计数值变成1

send函数take拿走这个1;

怎么封装的?

声明和定义结构体

把uart里面的这些函数封装起来

怎么封装函数

把这几个函数放入结构体中

这个结构体的成员函数如下,这样就能直接定义出这个结构体,用->来初始化、发数据、收数据

代码

#include "uart_device.h"
#include <stdio.h>
#include <string.h>extern struct UART_Device g_uart2_dev;
extern struct UART_Device g_uart4_dev;static struct UART_Device *g_uart_devices[] = {&g_uart2_dev, &g_uart4_dev};//根据名字遍历这个指针,返回结构体地址
struct UART_Device * GetUARDevice(char *name)
{int i = 0;for(i = 0; i < sizeof(g_uart_devices)/sizeof(g_uart_devices[0]); i++){if(!strcmp(name, g_uart_devices[i]->name))return g_uart_devices[i];}return NULL;
}
#ifndef __UART_DEVICE_H
#define __UART_DEVICE_H#include <stdint.h>struct UART_Device {char *name;int (*Init)( struct UART_Device *pDev, int baud, char parity, int data_bit, int stop_bit);int (*Send)( struct UART_Device *pDev, uint8_t *datas, uint32_t len, int timeout);int (*RecvByte)( struct UART_Device *pDev, uint8_t *data, int timeout);
};struct UART_Device *GetUARDevice(char *name);#endif /* __UART_DEVICE_H */
//任务函数
static void SPILCDTaskFunction( void *pvParameters )
{char bur[100];int cnt = 0;while(1){sprintf(bur, "lcd task test:%d" ,cnt++);//Draw_String(0, 0 , bur, 0x0000ff00, 0);vTaskDelay(1000);}}static void CH1_URAT2_TxTaskFunction( void *pvParameters )
{ uint8_t c = 0;struct UART_Device *pdev = GetUARDevice("uart2");pdev->Init(pdev , 115200, 'N', 8, 1);while(1){pdev->Send(pdev, &c, 1, 100);vTaskDelay(500);c++;}
}static void CH2_URAT4_RxTaskFunction( void *pvParameters )
{uint8_t c = 0;char bur[100];int cnt = 0;int err;struct UART_Device *pdev = GetUARDevice("uart4");pdev->Init(pdev , 115200, 'N', 8, 1);while(1){err = pdev->RecvByte(pdev, &c, 100);if(err == 0)//=0表示接收完成{sprintf(bur,"receive dataset : 0x:%02x, numember:%d",c, cnt++);Draw_String(0, 0, bur, 0x0000ff00, 0);}else{//HAL_UART_DMAStop(&huart4);//超时或迅出错则调用终止中断接收的函敿}}}/* USER CODE END FunctionPrototypes *//*** @brief  FreeRTOS initialization* @param  None* @retval None*/
void MX_FREERTOS_Init(void) {/* USER CODE BEGIN Init *//* USER CODE END Init *//* USER CODE BEGIN RTOS_MUTEX *//* add mutexes, ... *//* USER CODE END RTOS_MUTEX *//* USER CODE BEGIN RTOS_SEMAPHORES *//* add semaphores, ... *//* USER CODE END RTOS_SEMAPHORES *//* USER CODE BEGIN RTOS_TIMERS *//* start timers, add new ones, ... *//* USER CODE END RTOS_TIMERS *//* USER CODE BEGIN RTOS_QUEUES *//* add queues, ... *//* USER CODE END RTOS_QUEUES *//* creation of defaultTask */defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);/* USER CODE BEGIN RTOS_THREADS *//* add threads, ... */xTaskCreate(SPILCDTaskFunction, // 函数指针, 任务函数"spi_lcd_task", // 任务的名孿200, // 栈大尿,单位为word,10表示40字节NULL, // 调用任务函数时传入的参数osPriorityNormal, // 优先线NULL ); // 任务句柄, 以后使用它来操作这个任务xTaskCreate(CH1_URAT2_TxTaskFunction, // 函数指针, 任务函数"ch1_uart2_tx_task", // 任务的名孿200, // 栈大尿,单位为word,10表示40字节NULL, // 调用任务函数时传入的参数osPriorityNormal, // 优先线NULL ); // 任务句柄, 以后使用它来操作这个任务xTaskCreate(CH2_URAT4_RxTaskFunction, // 函数指针, 任务函数"ch2_uart4_rx_task", // 任务的名孿200, // 栈大尿,单位为word,10表示40字节NULL, // 调用任务函数时传入的参数osPriorityNormal, // 优先线NULL ); // 任务句柄, 以后使用它来操作这个任务/* USER CODE END RTOS_THREADS *//* USER CODE BEGIN RTOS_EVENTS *//* add events, ... *//* USER CODE END RTOS_EVENTS */}
static SemaphoreHandle_t g_UART2_TX_Semaphore;
static uint8_t g_uart4_rx_buf[100];//定义丿个buff来存接收到的数据
static QueueHandle_t g_xUART4_RX_Queue;//创建队列static SemaphoreHandle_t g_UART4_TX_Semaphore;
static uint8_t g_uart2_rx_buf[100];
static QueueHandle_t g_xUART2_RX_Queue;
struct UART_Device;//表示这是一个结构体类型//send callback
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{//数据返鿁完毕,中断函数会调用这个回调函敿if(huart == &huart2){xSemaphoreGiveFromISR(g_UART2_TX_Semaphore, NULL);}if(huart == &huart4){xSemaphoreGiveFromISR(g_UART4_TX_Semaphore, NULL);}}//receive callback
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{//数据返鿁完毕,中断函数会调用这个回调函敿if(huart == &huart4){//收到数据后把收到的数据存入buff,写队列for(int i = 0 ; i < 100; i++){xQueueSendFromISR(g_xUART4_RX_Queue,&g_uart4_rx_buf[i], NULL);}//重新启动DMA+IDLEHAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}if(huart == &huart2){//收到数据后把收到的数据存入buff,写队列for(int i = 0 ; i < 100; i++){xQueueSendFromISR(g_xUART2_RX_Queue,&g_uart2_rx_buf[i], NULL);}//重新启动DMA+IDLEHAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);	}
}//receive  void event,接收空闿,表示数据已经接收完成,但是还没到DMA接收设置的忿
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{if(huart == &huart4){//写队刿for(int i = 0 ; i < Size; i++){xQueueSendFromISR(g_xUART4_RX_Queue,&g_uart4_rx_buf[i], NULL);}//重新启动DMA+IDLEHAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);	}if(huart == &huart2){//写队刿for(int i = 0 ; i < Size; i++){xQueueSendFromISR(g_xUART2_RX_Queue,&g_uart2_rx_buf[i], NULL);}//重新启动DMA+IDLEHAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);	}
}//receive void error:重新启动DMA+IDLE
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{//重启DMA+IDLEif(huart == &huart4){HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);}if(huart == &huart2){HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);}}//读数据,app从队列中读数据不从串口读数据亿/**************/
/**************//*  uart4接收、uart2发送  */
int UART2_Send(struct UART_Device *pDev, uint8_t *datas,uint32_t len, int timeout)
{HAL_UART_Transmit_DMA(&huart2, datas, len);//wait Semaphore 信号量if(pdTRUE == xSemaphoreTake(g_UART2_TX_Semaphore,timeout))return 0;elsereturn -1;
}int UART4_GetData(struct UART_Device *pDev,uint8_t *pData, int timeout)
{if(pdPASS == xQueueReceive(g_xUART4_RX_Queue,pData, timeout))return 0;else return -1;
}int UART4_RX_Start(struct UART_Device *pDev, int baud, char parity, int data_bit, int stop_bit)
{//弿始前把上面定义好的队列创建处板if(!g_xUART2_RX_Queue) {g_xUART4_RX_Queue = xQueueCreate( 200, 1 );//启动接收HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);//收到的数据保存在哪里,要定义1个buff;收到后回调函数就会被调用//创建信号量g_UART4_TX_Semaphore = xSemaphoreCreateBinary();}return 0;
}/*****************/
/*  uart2接收、uart4发送  */
int UART2_GetData(struct UART_Device *pDev, uint8_t *pData, int timeout)
{if(pdPASS == xQueueReceive(g_xUART2_RX_Queue,pData, timeout))return 0;else return -1;
}int UART2_RX_Start(struct UART_Device *pDev, int baud, char parity, int data_bit, int stop_bit)
{if (!g_xUART2_RX_Queue){g_xUART2_RX_Queue = xQueueCreate(200, 1);g_UART2_TX_Semaphore = xSemaphoreCreateBinary();HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);}return 0;
}int UART4_Send(struct UART_Device *pDev, uint8_t *datas,uint32_t len, int timeout)
{HAL_UART_Transmit_DMA(&huart4, datas, len);//wait Semaphore 信号量if(pdTRUE == xSemaphoreTake(g_UART4_TX_Semaphore,timeout))return 0;elsereturn -1;
}struct UART_Device g_uart2_dev = {"uart2", UART2_RX_Start, UART2_Send, UART2_GetData};
struct UART_Device g_uart4_dev = {"uart4", UART4_RX_Start, UART4_Send, UART4_GetData};

编写遇到的问题

1、./Core/Src/usart.c(377): warning: passing 'volatile uint8_t [100]' to parameter of type 'uint8_t *' (aka 'unsigned char *') discards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]

2、undefined symbol

把static去掉后就好了

另一个文件

10.寄存器

串口通讯不许连续发送,串口为什么一次只发一个字节?

1、避免累计误差;

2、串口通讯是异步发送,就是发送方和接受方有各自的时钟,时钟不同步,时钟同步的话可以发好多个字节;

波特率、比特率

波特率表示每秒传输信号的状态数,如果一个波形传输一个bit,那就=bit率,每秒传输的二进制位

一个波形传输n个比特

波特率= n比特率

总之:

波特率: 1 秒内传输信号的状态数(波形数)。比特率: 1 秒内传输数据的 bit数。如果一个波形,能表示 N 个 bit,那么:波特率 * N = 比特率。
 

通讯协议

并行8根线一次发8位

串行通信一根线发

单工,只能单向

双工双向,半双工一条通道接受和发送不能同时工作

全双工两个通道可以,同时收发

FIFO

FIFO(First In First Out,即先入先出),是一种数据缓冲器。先被写入的数据会按顺序先被读出。FIFO可看做一个管道,有数据写入端口和 数据读取端口:

设置异步通信

设置数据位,校验位、波特率、停止位

memset

11.USB的四类传输方式

12.Modbus的四种存储区(Modbus是一主多从的通信协议)

13.

Vim代码编辑器编辑代码,再经过gcc代码编译器编译生成可执行文件,再./执行文件

14.

Freertos在不同串口的通道同时使用LCD进行屏显时,需要设置互斥量来建立互斥锁(具体为可以在上一段程序使用LCD时,下一段程序无限等待(portMAX_DELAY)),在上一段程序完成使用后,要释放互斥锁!

15.u-boot是最常用的bootloader

16.eMMC、Nand Flash都属于Flash,Flash的具体类别如下:

单片机板子的Flash中,已预先包含Bootloader和APP程序(Bootloader存在的意义为帮助APP程序实现更新或重装,原因见下文14)

17.Bootloader在APP程序下载更新或重装中存在的意义

18.bootloader下载更新或重装APP程序的思路框架

上图6的启动程序的具体方法如下图:


http://www.ppmy.cn/news/1516478.html

相关文章

C#/.NET/.NET Core技术前沿周刊 | 第 2 期(2024年8.19-8.25)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿&…

MFC之word操作

MFC对word操作 背景说明 当对程序的内容进行输出时&#xff0c;比如自定义对象属性描述或者注释&#xff08;详细设计&#xff09;生成文档时&#xff0c;如果采用手动输入会比较麻烦&#xff0c;并且当程序变动时&#xff0c;需要再一次修改对应文档&#xff0c;作为程序员做…

修复 502 Bad Gateway 错误的 6 种方法

通常&#xff0c;我们在使用网站时可能会遇到一系列错误。有些非常常见&#xff0c;例如 404&#xff0c;有些则不太常见&#xff0c;例如 101。这些被称为 HTTP 状态代码。其中&#xff0c;502 错误是某种服务器错误。那么&#xff0c;让我们先了解一下 Bad Gateway 502 的含义…

EazyDraw for Mac 矢量图绘制设计软件

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功 三、运行测试安装完成&#xff01;&#xff01;&#xff01; 效果 一、下载软件 下载软件…

SpringMvc 以配置类的形式代替xml文件

1、配置类 1.1、创建Mvc 项目之后创建 MyWebApplicationInitializer 类 实现接口 WebApplicationInitializer public class MyWebApplicationInitializer implements WebApplicationInitializer {Overridepublic void onStartup(ServletContext servletContext) throws Serv…

通过Spring Boot创建项目

目录 引言 一、创建新项目 二、通过spring boot创建顾客查询的项目 1.实体类: 2.mapper接口 3.service服务层接口 4.service服务层接口实现类 5.mapper映射文件 三、可能遇到的问题 引言 在通过之前ssm框架的学习后&#xff0c;你是否会感觉ssm的配置过多&#xff0c…

Redis 的 主从复制

目录 1 Redis 主从复制介绍 2 Redis主从复制原理 2.1 主从同步过程 3 Redis实现主从复制 3.1 环境配置 3.2 修改各节点的配置文件 3.2.1 MASTER 3.2.2 SLAVE 3.3.3 重启Redis 3.3 查看是否实现了主从复制 3.3.1 MASTER 3.3.2 SLAVE 3.3.3 Redis 常用操作 3.3.4 数据添加查看…

Yolo环境搭建(深度学习基础环境)

需要安装的东西 CUDAcuDnn魔法 一、CUDA安装(Windows10环境) 第一&#xff1a;下载驱动 第二&#xff1a;查看显卡支持的最高CUDA的版本&#xff0c;以便下载对应的CUDA安装包 第三&#xff1a;确定CUDA版本对应的cuDNN版本&#xff0c;这个其实不用太关注&#xff0c;因为…

【解析几何笔记】9. 向量的内积运算

9. 向量的内积运算 定义&#xff1a;有向量 α , β \pmb{\alpha},\pmb{\beta} α,β&#xff0c; α ⋅ β ∣ α ∣ ∣ β ∣ ⋅ cos ⁡ < α , β > \pmb{\alpha}\cdot\pmb{\beta}|\pmb{\alpha}||\pmb{\beta}|\cdot\cos<\pmb{\alpha},\pmb{\beta}> α⋅β∣α…

Qt编写贪吃蛇小游戏完整项目

文章目录 前言一、Qt环境准备二、编写思路三、编写代码1、开始游戏界面代码1.1、绘制界面1.2、界面基本配置 2、选择难度界面代码3、游戏房间界面制作3.1、界面基础配置3.2、提前配置类中的成员变量3.2.1、QRectF 3.3、检测游戏是否结束的方法3.4、蛇移动的实现3.4.1、蛇向上移…

【赵渝强老师】执行MySQL的冷备份与冷恢复

冷备份是指发生在数据库已经正常关闭的情况下进行的备份。由于此时数据库已经关闭&#xff0c;通过冷备份可以将数据库的关键性文件拷贝到另外存储位置。冷备份因为只是拷贝文件&#xff0c;因此备份的速度非常快。在执行恢复时&#xff0c;只需将文件再拷贝回去就可以很容易恢…

CPU利用率和CPU负载的区别

CPU利用率和负载虽然相关,但确是两个不同的概念。 CPU利用率 CPU利用率表示CPU实际工作时间与总时间的比率,通常以百分比表示。范围是0% 到 100%&#xff0c;CPU利用率的含义是表示CPU在给定时间内实际执行指令的时间比例&#xff0c;举个例子: 70% 的CPU利用率意味着在某个时…

TCP、UDP

端口号: 端口号: 16位数值(unsigned short ) //0~65535 (65536个数) //标示一个进程 TCP和 UDP 的端口号是独立的 端口号: (1) 作用:唯一的标识一个进程 每一个应用程序进程有一个端口号&#xff0c; 通讯时区分数据包属于哪个应…

硬件面试经典 100 题(81~90)题

81、请问下图电路中二极管 D1、D2 有什么作用&#xff1f; 在 Vi 输入电压接近于零时&#xff0c;D1、D2 给三极管 T1、T2 提供偏置电压&#xff0c;使 T1、T2 维持导通&#xff0c;以消除交越失真。 陈氏解释 这道题参见&#xff1a;硬件面试经典 100 题&#xff08;51~70 题…

Vue3 后台管理系统项目 前端部分

这里写目录标题 1 创建Vue3项目1.1 相关链接1.2 Vue Router1.3 Element1.4 scss1.5 mitt1.6 axios1.7 echarts1.8 配置vite.config.js 2 CSS部分2.1 样式穿透2.2 :style &#xff1a;在样式中使用插值语法 3. ElementUI3.1 rules&#xff1a; 数据验证3.2 修改element.style中的…

信号分解|基于北方苍鹰优化变分模态分解的时序信号分解Matlab程序NGO-VMD

信号分解|基于北方苍鹰优化变分模态分解的时序信号分解Matlab程序NGO-VMD 文章目录 一、基本原理二、实验结果三、核心代码四、代码获取五、总结 信号分解|基于北方苍鹰优化变分模态分解的时序信号分解Matlab程序NGO-VMD 一、基本原理 NGO-VMD结合了北方苍鹰优化算法&#xff…

移动端爬虫学习记录

免责声明 本文旨在探讨移动端爬虫技术的应用和挑战&#xff0c;仅供教育和研究用途。请确保在合法合规的框架内使用爬虫技术&#xff0c;遵循相关法律法规和网站的使用条款。作者不对因使用本文内容而产生的任何法律或安全问题承担责任。 1、初识移动端爬虫 学习移动端爬虫的原…

7. Java 中 HashMap 的扩容机制是怎样的?

​​​​​​HashMap 是基于哈希表的数据结构&#xff0c;其容量是动态调整的。当存储的元素数量增加时&#xff0c;为了保持较好的性能&#xff0c;HashMap 需要进行扩容。HashMap 的扩容机制是为了减少哈希碰撞&#xff0c;提高查询效率。 1. 初始容量和负载因子 初始容量&a…

Android 退出app方式(回忆录)

一、点击返回键或者设备back键调用finish private void back(){finish(); }或Overridepublic void onBackPressed() {super.onBackPressed();}二、结束进程 android.os.Process.killProcess(android.os.Process.myPid()); 三、方法二exit结束java虚拟机 System.exit(0); 四…

uniapp中路由的基本使用方法、参数传递方式以及路由拦截与权限控制

一、概述 在uniapp开发中&#xff0c;路由是非常重要的一个方面&#xff0c;它可以实现页面之间的跳转和传递参数。本文将介绍uniapp中路由的使用技巧&#xff0c;并给出具体的代码示例。 二、uniapp路由的基本使用 在uniapp中&#xff0c;路由的基本使用可以通过uni.navigate…