嵌入式Linux学习笔记

news2024/12/22 14:43:29

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+IDLE
		HAL_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+IDLE
		HAL_UARTEx_ReceiveToIdle_DMA(&huart4, g_uart4_rx_buf, 100);
		
	}
		
}

//void error:重新启动DMA+IDLE
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	//重启DMA+IDLE
	HAL_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)
	{
		//一开头就调用这个函数来调用到IDLE
		UART4_RX_Start();
		
		err = UART4_GetData(&c);//读到的数据保存在c
		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);//超时或迅出错则调用终止中断接收的函敿
		}
		
	}
		
}

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+IDLE
		HAL_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+IDLE
		HAL_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+IDLE
		HAL_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+IDLE
		HAL_UARTEx_ReceiveToIdle_DMA(&huart2, g_uart2_rx_buf, 100);	
	}
}

//receive void error:重新启动DMA+IDLE
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	//重启DMA+IDLE
	if(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;
		else
			return -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;
		else
			return -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.coloradmin.cn/o/2076986.html

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

相关文章

常见错误导引 不锈钢螺钉的正确选购和使用分析

紧固件或螺钉是用于固定物体的机械工具。它们用于各种场景&#xff0c;从建造房屋、用具、玩具等。紧固件由多种材料制成&#xff0c;所有这些材料都有特定用途紧固件和用途。一些用于制造螺丝的材料包括不锈钢、铁、铜、铝和塑料。它通常会进行某种表面处理以提高其防锈性和/或…

day-40 合并区间

思路 将二维数组按照第一列升序排列&#xff0c;把intervals[0][0]作为第一个区间的起点&#xff0c;将 intervals[0][1]和intervals[1][0]进行比较&#xff0c;如果intervals[0][1]<intervals[1][0]&#xff0c;则不能合并&#xff0c;否则可以合并&#xff0c;将Math.max(…

绝对不能错过的60个Python日常高频写法总结!

一、 数字 1 求绝对值 绝对值或复数的模 In [1]: abs(-6)Out[1]: 62 进制转化 十进制转换为二进制&#xff1a; In [2]: bin(10)Out[2]: 0b1010十进制转换为八进制&#xff1a; In [3]: oct(9)Out[3]: 0o11十进制转换为十六进制&#xff1a; In [4]: hex(15)Out[4]: 0xf…

[ICS] 物理安全

工业控制系统安全气泡类比 这个理念是&#xff0c;为了防御那些无法更新到最新安全控制措施的旧系统&#xff0c;或者由于设备资源有限而无法处理安全控制措施的系统&#xff0c;帮助可视化这种设备的安全策略可以将它们放置在一个肥皂泡或玻璃泡中。泡中的系统和设备彼此信任…

Spring Cloud Stream与Kafka(一)

Spring Cloud Stream与Kafka&#xff08;一&#xff09; ​ 在实际开发过程中&#xff0c;消息中间件用于解决应用解耦&#xff0c;异步消息&#xff0c;流量削峰等问题&#xff0c;实现高可用、高性能、可伸缩和最终一致性架构。不同的消息中间件实现方式不同&#xff0c;内部…

遥感反演保姆级教程:SPSS筛选因子之后如何采用python建模和反演整个研究区?(以反演生物量为例)

SPSS筛选因子之后如何采用python建模和反演整个研究区?&#xff08;以反演生物量为例&#xff09; 引言 在遥感数据分析中&#xff0c;因子筛选和建模是关键步骤。筛选出与目标变量&#xff08;如生物量&#xff09;显著相关的因子&#xff0c;不仅可以提高模型的预测精度&a…

编程世界的平衡术:日常编码与自我提升的和谐共生

前言 在快速迭代的编程世界中&#xff0c;程序员的角色日益复杂且充满挑战&#xff0c;他们不仅是代码的编织者&#xff0c;更是技术进步的推动者。面对日常编码工作的繁重与个人成长的迫切需求&#xff0c;寻找两者之间的平衡点成为了每位程序员必须深思的问题。以下是我的详细…

C++初学者指南-5.标准库(第二部分)–特殊容器

C初学者指南-5.标准库(第二部分)–特殊容器 pair<A , B> 包含两个相同或不同类型的值 tuple<A , B> C11 包含许多相同或不同类型的值 optional C17 包含一个类型为 T 的值或没有值 variant<A,B,C,…> C17 包含一个类型为A、B或C的值…… any C17 包含任…

《花100块做个摸鱼小网站! 》第四篇—前端应用搭建和完成第一个热搜组件

⭐️基础链接导航⭐️ 服务器 → ☁️ 阿里云活动地址 看样例 → &#x1f41f; 摸鱼小网站地址 学代码 → &#x1f4bb; 源码库地址 一、前言 在本系列文章的早期章节中&#xff0c;我们已经成功地购买了服务器并配置了MySQL、Redis等核心中间件。紧接着&#xff0c;我们不仅…

用AI来学习英语口语(白嫖,所以稍微麻烦些)

写在前面 本文看下如何使用AI来免费学习英语口语。 1&#xff1a;正文 首先&#xff0c;我们点击这里来到一个对话窗口&#xff0c;你可以在这个窗口中使用英语来询问你的问题&#xff0c;比如what can i do when i am not happy&#xff1a; 接着复制机器人回答内容&#…

datawhale AI夏令营第五期 深度学习入门 Task1 了解机器学习

机器学习基础 定义 学习一般是只有人才具备的能力&#xff0c;机器学习就是通过某种方式让机器具备人才有的学习能力&#xff0c;这里的某种方式是机器具备找一个函数的能力 比如说证件照背景颜色更换&#xff0c;那么机器需要找到图片中的背景在哪里&#xff0c;再替换成目…

pandas操作Excel文件

pandas操作Excel文件 一、前言二、指定读取的工作表与header设置2.1指定工作表2.2header设置 三、读取Excel数据3.1iloc读取数据3.2read_excel读取数据3.3loc读取数据 四、DataFrame数据筛选4.1根据列标签对整列进行筛选4.2使用iloc对区域进行筛选4.3自定义筛选 五、DataFrame类…

2024年8月26日(线上考试系统,虚拟化技术部署,使用link)

[rootdocker ~]# systemctl start docker [rootdocker ~]# docker pull mysql 一、线上考试系统 虚拟化技术部署 1、部署前端服务器 project_exam_system.sql数据库文件 dist网络资源 1.将资源上传到服务器 C:\Users\89765>scp -r "D:\青岛实训\project_exam_system\d…

C语言典型例题52

《C程序设计教程&#xff08;第四版&#xff09;——谭浩强》 题目&#xff1a; 例题4.4 相传古代印度国王舍罕要褒奖他聪明能干的宰相达依尔&#xff08;国际象棋发明者&#xff09;&#xff0c;问他需要什么&#xff0c;达依尔回答说&#xff1a;“国王只要在国际象棋的棋盘的…

Shader 中的渲染顺序

1、深度测试和深度写入 有了深度测试和深度写入发挥作用让我们不需要关心不透明物体的渲染顺序比如一个物体A 挡住了 物体B&#xff0c;即使底层逻辑中 先渲染A&#xff0c;后渲染B&#xff0c;我们也不用担心 B的颜色会把A覆盖&#xff0c;因为在进行深度测试时&#xff0c;远…

电池管理系统SOX算法资料优化目录2024.8.26

这篇文章主要写一下这一次更新的几个地方&#xff0c;有对原来的代码及模型进行优化的部分&#xff0c;也有新增加的代码和模型&#xff0c;我就把几个比较典型的给列了出来。但是还有好多的更新没有在下面展示出来&#xff0c;因为一个个展示出来太复杂了。如果你对更新的内容…

如何使用ssm实现基于 SSM 框架的宠物用品电子商务平台设计与实现+vue

TOC ssm258基于 SSM 框架的宠物用品电子商务平台设计与实现vue 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科…

黑神话悟空妖怪平生录

黑神话悟空是一部特别好玩的单机游戏。上一个我这么喜欢的国产单机还是古剑奇谭三。 虽然黑神话的战斗系统和地图系统尚不完善&#xff0c;但是这里面的游记是真的做得很认真。 203个妖怪&#xff0c;203首小诗&#xff0c;203个妖生故事&#xff0c;带你去看妖怪的喜怒哀乐。…

freemarker模版注入

Freemarker模版注入漏洞 模版注入漏洞根因&#xff08;SSTI&#xff0c;服务器端模版注入&#xff09;freemarker介绍Freemarker模版注入漏洞关键点漏洞复现环境引入依赖poc 修复方案完整代码&#xff08;包含修复&#xff09;参考 模版注入漏洞根因&#xff08;SSTI&#xff0…

乾坤大挪移--将一个混乱的excel分类整理的辅助VBA代码

excel 乾坤大挪移 你不需要将工作表手动分类&#xff1b; 只需要在”已整理“的标题行增加标题列&#xff0c; listbox会自动获取”已整理“sheet中的标题列&#xff0c;并列出来 你只需要选中同一列中的单元格&#xff0c;点击想移动到的列表的类别&#xff0c;双击或者点…