stm32----三----UART_DMA学习记录(1)

目录

“等待可以配置”

while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){}
//等待DMA可配置 ,disable时才可以配置,able时是在使用中,没法配置

//par:外设地址,这例程里为DATA寄存器的地址

uint32_t DMA_MemoryBurst;

MBURST:存储器突发传输配置 (Memory burst transfer configuration)
这些位将由软件置 1 和清零。
00:单次传输
01: INCR4( 4 个节拍的增量突发传输)
10: INCR8( 8 个节拍的增量突发传输)
11: INCR16( 16 个节拍的增量突发传输)
这些位受到保护,只有 EN 为“0”时才可以写入
在直接模式中,当位 EN =“1”时,这些位由硬件强制置为 0x0。

//指定内存传输的突发传输配置。
它指定在单个不可中断续中要传输的数据量
事务。该参数的值可以是@ref DMA_memory_burst
@说明只有启用了地址增量模式,才允许使用突发模式。
#define IS_DMA_MEMORY_BURST(BURST) (((BURST) == DMA_MemoryBurst_Single) || \
                                    ((BURST) == DMA_MemoryBurst_INC4)  || \
                                    ((BURST) == DMA_MemoryBurst_INC8)  || \
                                    ((BURST) == DMA_MemoryBurst_INC16))
u8 sendbuf[1024];
u8 receivebuf[1024];
static void _uart1_dma_configuration()
{
  DMA_InitTypeDef DMA_InitStructure;

  /* DMA1 Channel6 (triggered by USART1 Rx event) Config */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 ,
                        ENABLE);

  /* DMA1 Channel5 (triggered by USART1 Rx event) Config */
  DMA_DeInit(DMA1_Channel5);
  DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;// 初始化外设地址,相当于“哪家快递”  
  DMA_InitStructure.DMA_MemoryBaseAddr =(u32)receivebuf;// 内存地址,相当于几号柜
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;//外设作为数据来源,即为收快递
  DMA_InitStructure.DMA_BufferSize = DMASIZE ;// 缓存容量,即柜子大小
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不递增,即柜子对应的快递不变
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;// 内存递增
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //外设字节宽度,即快递运输快件大小度量(按重量算,还是按体积算) 
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;// 内存字节宽度,即店主封装快递的度量(按重量,还是按体质进行封装)
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 正常模式,即满了就不在接收了,而不是循环存储
  DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;// 优先级很高,对应快递就是加急
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 内存与外设通信,而非内存到内存 
  DMA_Init(DMA1_Channel5, &DMA_InitStructure);// 把参数初始化,即拟好与快递公司的协议

  DMA_Cmd(DMA1_Channel5, ENABLE);// 启动DMA,即与快递公司签订合同,正式生效

  /* DMA1 Channel4 (triggered by USART1 Tx event) Config */
  DMA_DeInit(DMA1_Channel4);
  DMA_InitStructure.DMA_PeripheralBaseAddr = USART1_DR_Base;  // 外设地址,串口1, 即发件的快递
  DMA_InitStructure.DMA_MemoryBaseAddr =(u32)sendbuf;// 发送内存地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;// 外设为传送数据目的地,即发送数据,即快递是发件
  DMA_InitStructure.DMA_BufferSize = 0;  //发送长度为0,即未有快递需要发送
  DMA_Init(DMA1_Channel4, &DMA_InitStructure);//初始化

  USART_ITConfig(USART1, USART_IT_TC, ENABLE);// 使能串口发送完成中断
  USART_DMACmd(USART1, USART_DMAReq_Tx|USART_DMAReq_Rx, ENABLE);// 使能DMA串口发送和接受请求
}

问题思考:(尽量多用多说英语吧,都快忘完了)

哪些中断标志位是要清理的?什么时候清理?clear放函数头函数尾先后有别吗?IDLE“空闲”的准确定义是什么?DMA具体说来是怎么捣腾数据的?

will dma clear it’s memory array automaticly each call?

—:No, this is a common array, the last massage will remain , only if i write:

memset(rx_buffer,0,rx_len);// set the rx_buffer[0]~[re_len] into 0

ps:发现插入图片其实截图ctrl+v就行,就说csdn怎么会那么憨
在这里插入图片描述

the uart_dma could only receive 1 word though i write many,but been good after a whlie???

在这里插入图片描述
and it will be late than the newest message for exactly one step??? like a message remain in the memory ?
写jb英文!!!看不懂!!不会写!!垃圾!!难受!!

not so convenient to ouerwatch, set all these valuable into struct;

globle_interrupt and IDLE_interrupt??

莫名其妙又卡到error_handler里了??

离谱,我是sa bi…因为抄来的函数封装的不好,外面本来要调用&huart3,里面实际是&huart2,还TM有个error_handler调用。瞎jiba封装。

初步抄好了uart2,3,这次提前总的把变量名都改好再移植进去。(借助文档的ctrl.f高亮修改数字很方便!!!)

例如原本是
volatile uint8_t rx_len = 0; //接收一帧数据的长度
volatile uint8_t recv_end_flag = 0; //一帧数据接收完成标志
uint8_t rx_buffer[100]={0}; //接收数据缓存数组
。。。。。。。。。。。。。。。。。。。.。。。。。等等
改成:
//

【u1:】

//
main.c

volatile uint8_t rx_len1 = 0;  //接收一帧数据的长度
volatile uint8_t recv_end_flag1 = 0; //一帧数据接收完成标志
uint8_t rx_buffer1[100]={0};  //接收数据缓存数组

main()

//下方为自己添加的代码
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能IDLE中断

//DMA接收函数,此句一定要加,不加接收不到第一次传进来的实数据,是空的,且此时接收到的数据长度为缓存器的数据长度
	HAL_UART_Receive_DMA(&huart1,rx_buffer1,BUFFER_SIZE1);

main.h

#define BUFFER_SIZE1  100  
extern  volatile uint8_t rx_len1 ;  //接收一帧数据的长度
extern volatile uint8_t recv_end_flag1; //一帧数据接收完成标志
extern uint8_t rx_buffer1[100];  //接收数据缓存数组

main() whlie(1)

 if(recv_end_flag1 == 1)  //接收完成标志
		{
            HAL_UART_Transmit_DMA(&huart1, rx_buffer1,rx_len1);
			rx_len1 = 0;//清除计数
			recv_end_flag1 = 0;//清除接收结束标志位

				memset(rx_buffer1,0,rx_len1);//这里等会再上调
  }
		HAL_UART_Receive_DMA(&huart1,rx_buffer1,BUFFER_SIZE1);//重新打开DMA接收

it.c UART1_IQR_Handler()

    uint32_t tmp_flag = 0;
	uint32_t temp;
	tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
	if((tmp_flag != RESET))//idle标志被置位
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);//清除标志位
		//temp = huart1.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
		//temp = huart1.Instance->DR; //读取数据寄存器中的数据
		//这两句和上面那句等效
		HAL_UART_DMAStop(&huart1); //
		temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);// 获取DMA中未传输的数据个数 ,要把usart改成uart
		//temp  = hdma_usart1_rx.Instance->NDTR;//读取NDTR寄存器 获取DMA中未传输的数据个数,
		//这句和上面那句等效
		rx_len1 =  BUFFER_SIZE1 - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
		recv_end_flag1 = 1;	// 接受完成标志位置1	
	 }

插入的usart1

			for(int i=0;i<50;i++)
			{
			  test_2[i]=test_2_backup[i];
			}
			strcat(test_2,test_1);
			strcat(test_2,rx_buffer1);

      HAL_UART_Transmit_DMA(&huart2, (uint8_t *)test_2,sizeof(test_2));	
      
      //3
      			for(int i=0;i<50;i++)
			{
			  test_3[i]=test_3_backup[i];
			}
			strcat(test_3,test_1);
			strcat(test_3,rx_buffer1);

      HAL_UART_Transmit_DMA(&huart3, (uint8_t *)test_3,sizeof(test_3));			


//4
			for(int i=0;i<50;i++)
			{
			  test_4[i]=test_4_backup[i];
			}
			strcat(test_4,test_1);
			strcat(test_4,rx_buffer1);

      HAL_UART_Transmit_DMA(&huart4, (uint8_t *)test_4,sizeof(test_4));		

//5
			for(int i=0;i<50;i++)
			{
			  test_5[i]=test_5_backup[i];
			}
			strcat(test_5,test_1);
			strcat(test_5,rx_buffer1);

      HAL_UART_Transmit_DMA(&huart5, (uint8_t *)test_5,sizeof(test_5));	
      //6
      			for(int i=0;i<50;i++)
			{
			  test_6[i]=test_6_backup[i];
			}
			strcat(test_6,test_1);
			strcat(test_6,rx_buffer1);

      HAL_UART_Transmit_DMA(&huart6, (uint8_t *)test_6,sizeof(test_6));	
      //7
      			for(int i=0;i<50;i++)
			{
			  test_7[i]=test_7_backup[i];
			}
			strcat(test_7,test_1);
			strcat(test_7,rx_buffer1);

      HAL_UART_Transmit_DMA(&huart7, (uint8_t *)test_7,sizeof(test_7));	
     	

不知道能不能写一个全自动检测的软件,也省得亲自瞅了;
//

【u4:】

//
main.c

volatile uint8_t rx_len4 = 0;  //接收一帧数据的长度
volatile uint8_t recv_end_flag4 = 0; //一帧数据接收完成标志
uint8_t rx_buffer4[100]={0};  //接收数据缓存数组

main()

//下方为自己添加的代码
	__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE); //使能IDLE中断

//DMA接收函数,此句一定要加,不加接收不到第一次传进来的实数据,是空的,且此时接收到的数据长度为缓存器的数据长度
	HAL_UART_Receive_DMA(&huart4,rx_buffer4,BUFFER_SIZE4);

main.h:

	#define BUFFER_SIZE4  100  
	extern  volatile uint8_t rx_len4 ;  //接收一帧数据的长度
	extern volatile uint8_t recv_end_flag4; //一帧数据接收完成标志
	extern uint8_t rx_buffer4[100];  //接收数据缓存数组

main() whlie(1):

 if(recv_end_flag4 == 1)  //接收完成标志
		{
            HAL_UART_Transmit_DMA(&huart4, rx_buffer4,rx_len4);
			rx_len4 = 0;//清除计数
			recv_end_flag4 = 0;//清除接收结束标志位

				memset(rx_buffer4,0,rx_len4);//这里等会再上调
  }
		HAL_UART_Receive_DMA(&huart4,rx_buffer4,BUFFER_SIZE4);//重新打开DMA接收

it.c UART4_IQR_Handler():

    uint32_t tmp_flag = 0;
	uint32_t temp;
	tmp_flag =__HAL_UART_GET_FLAG(&huart4,UART_FLAG_IDLE); //获取IDLE标志位
	if((tmp_flag != RESET))//idle标志被置位
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart4);//清除标志位
		//temp = huart1.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
		//temp = huart1.Instance->DR; //读取数据寄存器中的数据
		//这两句和上面那句等效
		HAL_UART_DMAStop(&huart4); //
		temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart4_rx);// 获取DMA中未传输的数据个数 ,要把usart改成uart
		//temp  = hdma_usart1_rx.Instance->NDTR;//读取NDTR寄存器 获取DMA中未传输的数据个数,
		//这句和上面那句等效
		rx_len4 =  BUFFER_SIZE4 - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
		recv_end_flag4 = 1;	// 接受完成标志位置1	
	 }

//

【u5:】

//

volatile uint8_t rx_len5 = 0;  //接收一帧数据的长度
volatile uint8_t recv_end_flag5 = 0; //一帧数据接收完成标志
uint8_t rx_buffer5[100]={0};  //接收数据缓存数组
//下方为自己添加的代码
	__HAL_UART_ENABLE_IT(&huart5, UART_IT_IDLE); //使能IDLE中断

//DMA接收函数,此句一定要加,不加接收不到第一次传进来的实数据,是空的,且此时接收到的数据长度为缓存器的数据长度
	HAL_UART_Receive_DMA(&huart5,rx_buffer5,BUFFER_SIZE5);

#define BUFFER_SIZE5  100  
extern  volatile uint8_t rx_len5 ;  //接收一帧数据的长度
extern volatile uint8_t recv_end_flag5; //一帧数据接收完成标志
extern uint8_t rx_buffer5[100];  //接收数据缓存数组
 if(recv_end_flag5 == 1)  //接收完成标志
		{
            HAL_UART_Transmit_DMA(&huart5, rx_buffer5,rx_len5);
			rx_len5 = 0;//清除计数
			recv_end_flag5 = 0;//清除接收结束标志位

				memset(rx_buffer5,0,rx_len5);//这里等会再上调
  }
		HAL_UART_Receive_DMA(&huart5,rx_buffer5,BUFFER_SIZE5);//重新打开DMA接收
    uint32_t tmp_flag = 0;
	uint32_t temp;
	tmp_flag =__HAL_UART_GET_FLAG(&huart5,UART_FLAG_IDLE); //获取IDLE标志位
	if((tmp_flag != RESET))//idle标志被置位
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart5);//清除标志位
		//temp = huart1.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
		//temp = huart1.Instance->DR; //读取数据寄存器中的数据
		//这两句和上面那句等效
		HAL_UART_DMAStop(&huart5); //
		temp  =  __HAL_DMA_GET_COUNTER(&hdma_uart5_rx);// 获取DMA中未传输的数据个数 ,要把usart改成uart
		//temp  = hdma_usart1_rx.Instance->NDTR;//读取NDTR寄存器 获取DMA中未传输的数据个数,
		//这句和上面那句等效
		rx_len5 =  BUFFER_SIZE5 - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
		recv_end_flag5 = 1;	// 接受完成标志位置1	
	 }

//

【u6:】

//
main.c

volatile uint8_t rx_len6 = 0;  //接收一帧数据的长度
volatile uint8_t recv_end_flag6 = 0; //一帧数据接收完成标志
uint8_t rx_buffer6[100]={0};  //接收数据缓存数组

main()

//下方为自己添加的代码
	__HAL_UART_ENABLE_IT(&huart6, UART_IT_IDLE); //使能IDLE中断

//DMA接收函数,此句一定要加,不加接收不到第一次传进来的实数据,是空的,且此时接收到的数据长度为缓存器的数据长度
	HAL_UART_Receive_DMA(&huart6,rx_buffer6,BUFFER_SIZE6);

main.h

#define BUFFER_SIZE6  100  
extern  volatile uint8_t rx_len6 ;  //接收一帧数据的长度
extern volatile uint8_t recv_end_flag6; //一帧数据接收完成标志
extern uint8_t rx_buffer6[100];  //接收数据缓存数组

main() whlie(1)

 if(recv_end_flag6 == 1)  //接收完成标志
		{
            HAL_UART_Transmit_DMA(&huart6, rx_buffer6,rx_len6);
			rx_len6 = 0;//清除计数
			recv_end_flag6 = 0;//清除接收结束标志位

				memset(rx_buffer6,0,rx_len6);//这里等会再上调
  }
		HAL_UART_Receive_DMA(&huart6,rx_buffer6,BUFFER_SIZE6);//重新打开DMA接收

it.c UART6_IQR_Handler()

    uint32_t tmp_flag = 0;
	uint32_t temp;
	tmp_flag =__HAL_UART_GET_FLAG(&huart6,UART_FLAG_IDLE); //获取IDLE标志位
	if((tmp_flag != RESET))//idle标志被置位
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart6);//清除标志位
		//temp = huart1.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
		//temp = huart1.Instance->DR; //读取数据寄存器中的数据
		//这两句和上面那句等效
		HAL_UART_DMAStop(&huart6); //
		temp  =  __HAL_DMA_GET_COUNTER(&hdma_usart6_rx);// 获取DMA中未传输的数据个数 ,要把usart改成uart
		//temp  = hdma_usart1_rx.Instance->NDTR;//读取NDTR寄存器 获取DMA中未传输的数据个数,
		//这句和上面那句等效
		rx_len6 =  BUFFER_SIZE6 - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
		recv_end_flag6 = 1;	// 接受完成标志位置1	
	 }

//

【u7:】

//

volatile uint8_t rx_len7 = 0;  //接收一帧数据的长度
volatile uint8_t recv_end_flag7 = 0; //一帧数据接收完成标志
uint8_t rx_buffer7[100]={0};  //接收数据缓存数组
//下方为自己添加的代码
	__HAL_UART_ENABLE_IT(&huart7, UART_IT_IDLE); //使能IDLE中断

//DMA接收函数,此句一定要加,不加接收不到第一次传进来的实数据,是空的,且此时接收到的数据长度为缓存器的数据长度
	HAL_UART_Receive_DMA(&huart7,rx_buffer7,BUFFER_SIZE7);//这个宏定义总是忘记修改数字

#define BUFFER_SIZE7  100  
extern  volatile uint8_t rx_len7 ;  //接收一帧数据的长度
extern volatile uint8_t recv_end_flag7; //一帧数据接收完成标志
extern uint8_t rx_buffer7[100];  //接收数据缓存数组
 if(recv_end_flag7 == 1)  //接收完成标志
		{
            HAL_UART_Transmit_DMA(&huart7, rx_buffer7,rx_len7);
			rx_len7 = 0;//清除计数
			recv_end_flag7 = 0;//清除接收结束标志位

				memset(rx_buffer7,0,rx_len7);//这里等会再上调
  }
		HAL_UART_Receive_DMA(&huart7,rx_buffer7,BUFFER_SIZE7);//重新打开DMA接收
    uint32_t tmp_flag = 0;
	uint32_t temp;
	tmp_flag =__HAL_UART_GET_FLAG(&huart7,UART_FLAG_IDLE); //获取IDLE标志位
	if((tmp_flag != RESET))//idle标志被置位
	{ 
		__HAL_UART_CLEAR_IDLEFLAG(&huart7);//清除标志位
		//temp = huart1.Instance->SR;  //清除状态寄存器SR,读取SR寄存器可以实现清除SR寄存器的功能
		//temp = huart1.Instance->DR; //读取数据寄存器中的数据
		//这两句和上面那句等效
		HAL_UART_DMAStop(&huart7); //
		temp  =  __HAL_DMA_GET_COUNTER(&hdma_uart7_rx);// 获取DMA中未传输的数据个数 ,要把usart改成uart
		//temp  = hdma_usart1_rx.Instance->NDTR;//读取NDTR寄存器 获取DMA中未传输的数据个数,
		//这句和上面那句等效
		rx_len7 =  BUFFER_SIZE7 - temp; //总计数减去未传输的数据个数,得到已经接收的数据个数
		recv_end_flag7 = 1;	// 接受完成标志位置1	
	 }

初版21年h750vb小板串口dma收发测试代码完成:

然后把这些变量都封装到结构体中方便watch window查看

其实不用为了查看而封装成结构体,因为全局变量也能用watch window看:
在这里插入图片描述
但是watch window 来不及看一些转瞬即逝的变化,怎么记下来?
打断点/set access breakpoint?【】

usart 和uart的区别?

在UART上追加同步方式的序列信号变换电路的产品,被称为
USART(Universal Synchronous Asynchronous Receiver Transmitter)通用同步/异步收发传输器

UART(Universal Asynchronous Receiver/Transmitter)通用异步收发传输器
,是一种异步收发传输器,是电脑硬件的一部分。它将要传输的资料在串行通信与并行通信之间加以转换。作为把并行输入信号转成串行输出信号的芯片,UART通常被集成于其他通讯接口的连结上。

连续的两个同串口HAL_UART_Transmit_DMA会导致第二个无法发送?

HAL_UART_Transmit_DMA(&huart5, data_1,   rx_len5);
HAL_UART_Transmit_DMA(&huart5, data___2, rx_len5);

可以用strcat拼成一句来规避,但是到底为什么会这样?
【】

不能在中断中调用HAL_Delay()

这是中断延时,且优先级最低,进不去,会卡死在HAL_get_tick()中
解决方法:
1:改优先级
2:while()
3:自己建一个1ms定时器中断写成延时函数?

【undone】

21年小板串口六能发消息但不能收消息(不进中断)

学长说这种情况一般换串口芯片就好了,以前也出现过。
震惊100年,坏的真巧妙。

Cubemx生成代码失败——中文路径

在这里插入图片描述
这种就会报错,有中文括号似乎也会报错,有空格会报错吗?不会。

git 可以通过本地仓库给自己做版本控制吗?

push挺麻烦的

?

在这里插入图片描述
发现是因为我没有规定正确的dma发送大小,(999刚好3个字节,只够发到B,而再多写几个数字就会多发成功几位)
在这里插入图片描述
用for(){a[]=b[]}的方式可以拼接字符数组和字符串,一个char(即uint8_t)对应一个字节:

for(int i=0;i<50;i++)
{
	test_2[25+i]=rx_buffer[i];//25改成27就能看到冒号了
}
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)test_2,sizeof(test_2));	

在这里插入图片描述
试着用strcat行不行:

strcat(test_2,rx_buffer);
//			for(int i=0;i<50;i++){
//			test_2[25+i]=rx_buffer[i];
//			}
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)test_2,sizeof(test_2));	

在这里插入图片描述
999 :ok的
就是担心会不会溢出出错: (溢出后会缩水到比设定内存还小的大小发送,只要不溢出就能正常发送)
几百个9:它没能成功发送那么多?太少了吧?我缓冲区100字节呢?而且响应很慢,
在这里插入图片描述
看来溢出后会缩水到比设定内存还小的大小发送,只要稍微少发点不溢出就能正常发送。

还是会有些奇怪的字符?
在这里插入图片描述
多试几次发现,各个串口插拔时的噪音都会激发中断,且有概率收到奇怪的字符,而串口4每次发送必会附加一个奇怪字符emmmmm

在这里插入图片描述
把这一板上传记录后再加个串口一的接受测试,

串口发送的中文为什么能正确回传??

这是发的信息堵车了??

在这里插入图片描述

卧槽接上遥控器就给我整hard_fault??

在这里插入图片描述
重启后是能反馈usart1的接收了,但是串口助手直接卡死了emmmmm:
在这里插入图片描述
我改低频率试试:一秒一次,也没掉帧
(为啥不掉?)
(但看不到收的内容,是溢出了吗?我记得是128)
在这里插入图片描述
扩大后还是什么都看不到

抄大疆开源吧:

RC_Ctl_t RC_Ctl;

uint8_t dbus_meta_data0[RX_BUFF_LENGH]__attribute__((at(0x24006000)));

//

extern RC_Ctl_t RC_Ctl; 

extern uint8_t dbus_meta_data0[RX_BUFF_LENGH],dbus_meta_data1[RX_BUFF_LENGH];

/****************接收机部分*********************/
//接收机数组大小 实际上是18个字节
#define RX_BUFF_LENGH 30
//接收机结构体接口
 typedef struct { 
   struct     {       
   uint16_t sw;
	 uint16_t ch0;       
   uint16_t ch1;       
   uint16_t ch2;      
   uint16_t ch3;      
   uint8_t  s1; 
	 uint8_t  s1_last; 
   uint8_t  s2;
	 uint8_t  s2_last; 
	 int16_t left_VR; //拨杆变换值
	 int16_t left_HR;
	 int16_t right_VR;
	 int16_t right_HR;
	 int16_t left_RR;//拨轮变化值
    }rc; 
 
   struct     {      
   int16_t x;       
   int16_t y;       
   int16_t z;         
   uint8_t press_l;     
   uint8_t press_r; 
	 uint8_t press_l_flag;     
   uint8_t press_r_flag; 
	 }mouse; 
 
    struct  {     
    uint16_t v;  
    }keyboard;
	uint8_t  key[18];
	uint8_t  keyflag[18];	
	uint32_t key_filter_cnt[18];
 }RC_Ctl_t; 

//

void Remote_deal(uint8_t * dbus_meta_data)
	{ 
				uint8_t correct_num=0;	
       		correct_num=0;
				if(((dbus_meta_data[0] | (dbus_meta_data[1] << 8)) & 0x07ff)<=1684 && ((dbus_meta_data[0] | (dbus_meta_data[1] << 8)) & 0x07ff)>=364)
					correct_num++;
				if((((dbus_meta_data[1] >> 3) | (dbus_meta_data[2] << 5)) & 0x07ff)<=1684 && (((dbus_meta_data[1] >> 3) | (dbus_meta_data[2] << 5)) & 0x07ff)>=364)
					correct_num++;
				if((((dbus_meta_data[2] >> 6) | (dbus_meta_data[3] << 2) |(dbus_meta_data[4] << 10)) & 0x07ff)<=1684 && (((dbus_meta_data[2] >> 6) | (dbus_meta_data[3] << 2) |(dbus_meta_data[4] << 10)) & 0x07ff)>=364)
					correct_num++;
				if((RC_Ctl.rc.ch3 = ((dbus_meta_data[4] >> 1) | (dbus_meta_data[5] << 7)) & 0x07ff)<=1684 && (RC_Ctl.rc.ch3 = ((dbus_meta_data[4] >> 1) | (dbus_meta_data[5] << 7)) & 0x07ff)>=364)
					correct_num++;
				if((((dbus_meta_data[5] >> 4)& 0x000C) >> 2)==1 || (((dbus_meta_data[5] >> 4)& 0x000C) >> 2)==2 || (((dbus_meta_data[5] >> 4)& 0x000C) >> 2)==3)
					correct_num++;
				if(((dbus_meta_data[5] >> 4)& 0x0003)==1 || ((dbus_meta_data[5] >> 4)& 0x0003)==2 || ((dbus_meta_data[5] >> 4)& 0x0003)==3)
					correct_num++;
				if(correct_num==6)	//数据完成性验证 
				{
				Check.Remote=0;    
					
				RC_Ctl.rc.ch0 = (dbus_meta_data[0]| (dbus_meta_data[1] << 8)) & 0x07ff; //!< Channel 0   高8位与低3位
				RC_Ctl.rc.ch1 = ((dbus_meta_data[1] >> 3) | (dbus_meta_data[2] << 5)) & 0x07ff; //!< Channel 1     高5位与低6位
				RC_Ctl.rc.ch2 = ((dbus_meta_data[2] >> 6) | (dbus_meta_data[3] << 2) |(dbus_meta_data[4] << 10)) & 0x07ff; //!< Channel 2
				RC_Ctl.rc.ch3 = ((dbus_meta_data[4] >> 1) | (dbus_meta_data[5] << 7)) & 0x07ff; //!< Channel 3
				RC_Ctl.rc.s1 = ((dbus_meta_data[5] >> 4)& 0x000C) >> 2; //!< Switch left
				RC_Ctl.rc.s2 = ((dbus_meta_data[5] >> 4)& 0x0003); //!< Switch right
        RC_Ctl.rc.sw=(uint16_t)(dbus_meta_data[16]|(dbus_meta_data[17]<<8))&0x7ff; 
					
  			RC_Ctl.rc.right_HR=(RC_Ctl.rc.ch0-1024);
				RC_Ctl.rc.right_VR=(RC_Ctl.rc.ch1-1024);
				RC_Ctl.rc.left_HR=(RC_Ctl.rc.ch2-1024);
			  RC_Ctl.rc.left_VR=(RC_Ctl.rc.ch3-1024);
					
					/***********按键映射*************/
	      RC_Ctl.mouse.x = dbus_meta_data[6]  | (dbus_meta_data[7] << 8);                    //!< Mouse X axis   
        RC_Ctl.mouse.y = dbus_meta_data[8]  | (dbus_meta_data[9] << 8);                    //!< Mouse Y axis     
        RC_Ctl.mouse.z = dbus_meta_data[10] | (dbus_meta_data[11] << 8);                  //!< Mouse Z axis   
        RC_Ctl.mouse.press_l = dbus_meta_data[12];                                        //!< Mouse Left Is Press ?   
        RC_Ctl.mouse.press_r = dbus_meta_data[13];                                        //!< Mouse Right Is Press ? 
				
			 if(RC_Ctl.mouse.x>25000)   RC_Ctl.mouse.x=25000;
			 if(RC_Ctl.mouse.x<-25000)  RC_Ctl.mouse.x=-25000;	
			 if(RC_Ctl.mouse.y>25000)   RC_Ctl.mouse.y=25000;
			 if(RC_Ctl.mouse.y<-25000)  RC_Ctl.mouse.y=-25000;
					
			  RC_Ctl.keyboard.v = dbus_meta_data[14]| (dbus_meta_data[15] << 8);  	//!< KeyBoard value   

			
				RC_Ctl.key_W=dbus_meta_data[14]&0x01;	
				RC_Ctl.key_S=(dbus_meta_data[14]>>1)&0x01;					
				RC_Ctl.key_A=(dbus_meta_data[14]>>2)&0x01;
				RC_Ctl.key_D=(dbus_meta_data[14]>>3)&0x01;					
				RC_Ctl.key_B=(dbus_meta_data[15]>>7)&0x01;
				RC_Ctl.key_V=(dbus_meta_data[15]>>6)&0x01;				
				RC_Ctl.key_C=(dbus_meta_data[15]>>5)&0x01;
				RC_Ctl.key_X=(dbus_meta_data[15]>>4)&0x01;					
				RC_Ctl.key_Z=(dbus_meta_data[15]>>3)&0x01;					
				RC_Ctl.key_G=(dbus_meta_data[15]>>2)&0x01;			
				RC_Ctl.key_F=(dbus_meta_data[15]>>1)&0x01;
				RC_Ctl.key_R=(dbus_meta_data[15])&0x01;													
				RC_Ctl.key_E=(dbus_meta_data[14]>>7)&0x01;
				RC_Ctl.key_Q=(dbus_meta_data[14]>>6)&0x01;
				RC_Ctl.key_ctrl=(dbus_meta_data[14]>>5)&0x01;
				RC_Ctl.key_shift=(dbus_meta_data[14]>>4)&0x01;
				
}

数据不完整??:

在这里插入图片描述
啊啊啊啊啊啊!突然想起来是波特率和字长不对!!!

似乎哪里拼错了:

今早临走前发现数据发过去的数据变成乱码,头疼了1个多小时,下午过来发现遥控器接受数据正常,检查发现是

1:每次发送完没有把缓冲区清零(数字零和字符零是不一样的)—放屁,后来试了,删不删都一样,,诡异啊,不知道为啥【】
2:不知道怎么回事把下图选项改成hex发送了,改回来就好了:
在这里插入图片描述

尝试能不能用发送hex 0的方式清空缓冲区,发现不能:

在这里插入图片描述

想试试双缓冲区模式

正点原子P908
STM32H7——HAL库的DMA双缓冲配置使用
一个免锁环形缓冲区的实现
一个严谨的STM32串口DMA发送&接收(1.5Mbps波特率)机制

为什么正点原子总是用自己写的延时?

如何测试串口到底有没有丢包?

双DMA缓冲和单DMA差异 + 内存保护的必要性

在这里插入图片描述

代码移植

__HAL_UART_ENABLE_IT(&huart2,UART_IT_IDLE);//使能串口空闲中断
	dma_M0_rx_callback=dma_M0_callback;
	dma_M1_rx_callback=dma_M1_callback;

//

#define Rx_Len 50
uint8_t Rx_Buffer[2][Rx_Len]

//

	HAL_DMAEx_MultiBufferStart(&hdma_usart2_rx,USART2->RDR,(uint32_t)&Rx_Buffer[0][0],(uint32_t)&Rx_Buffer[1][0],Rx_Len);

//

void (*dma_M0_rx_callback)(void);
void (*dma_M1_rx_callback)(void);
void dma_M0_callback(void);
void dma_M1_callback(void);

//

void USART2_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
//  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
if(__HAL_UART_GET_IT_SOURCE(&huart2,UART_IT_IDLE)!=RESET) //检测是否发生空闲中断
	{
		__HAL_UART_CLEAR_IDLEFLAG(&huart2);//清除中断标志位
		
	/* Current memory buffer used is Memory 0 */
      if((((DMA_Stream_TypeDef   *)hdma_usart2_rx.Instance)->CR & DMA_SxCR_CT) == 0U)
	  {
		  __HAL_DMA_DISABLE(&hdma_usart2_rx);
	       /* Transfer complete Callback for memory1 */
		  if(dma_M1_rx_callback!=NULL)dma_M1_rx_callback();
		__HAL_DMA_ENABLE(&hdma_usart2_rx);
	  }
      /* Current memory buffer used is Memory 1 */
      else
      {
		  __HAL_DMA_DISABLE(&hdma_usart2_rx);
            if(dma_M0_rx_callback!=NULL)
			dma_M0_rx_callback();
			
       /* Transfer complete Callback for memory0 */
		  __HAL_DMA_ENABLE(&hdma_usart2_rx);
      }
	}
  /* USER CODE END USART1_IRQn 1 */
}

//

在这里插入代码片

一个将整型数转换为字符数组并用memset拼接的c,c++例子:

#include <iostream>
#include<bits/stdc++.h>
#include <stdlib.h>
#include <stdio.h>
using namespace std;
char* itoa(int num,char* str,int radix);



int main()
{
    
	int a=123456;
	
	char arr[100]="abcd",str[200];
	strcat(arr,itoa(a,str,10));
	cout<<arr<<endl;
	memset(arr,0,100);
	cout<<arr<<endl;
	 
	return 0;
	
}



char* itoa(int num,char* str,int radix)
{
    char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//索引表
    unsigned unum;//存放要转换的整数的绝对值,转换的整数可能是负数
    int i=0,j,k;//i用来指示设置字符串相应位,转换之后i其实就是字符串的长度;转换后顺序是逆序的,有正负的情况,k用来指示调整顺序的开始位置;j用来指示调整顺序时的交换。
 
    //获取要转换的整数的绝对值
    if(radix==10&&num<0)//要转换成十进制数并且是负数
    {
        unum=(unsigned)-num;//将num的绝对值赋给unum
        str[i++]='-';//在字符串最前面设置为'-'号,并且索引加1
    }
    else unum=(unsigned)num;//若是num为正,直接赋值给unum
 
    //转换部分,注意转换后是逆序的
    do
    {
        str[i++]=index[unum%(unsigned)radix];//取unum的最后一位,并设置为str对应位,指示索引加1
        unum/=radix;//unum去掉最后一位
 
    }while(unum);//直至unum为0退出循环
 
    str[i]='\0';//在字符串最后添加'\0'字符,c语言字符串以'\0'结束。
 
    //将顺序调整过来
    if(str[0]=='-') k=1;//如果是负数,符号不用调整,从符号后面开始调整
    else k=0;//不是负数,全部都要调整
 
    char temp;//临时变量,交换两个值时用到
    for(j=k;j<=(i-1)/2;j++)//头尾一一对称交换,i其实就是字符串的长度,索引最大值比长度少1
    {
        temp=str[j];//头部赋值给临时变量
        str[j]=str[i-1+k-j];//尾部赋值给头部
        str[i-1+k-j]=temp;//将临时变量的值(其实就是之前的头部值)赋给尾部
    }
 
    return str;//返回转换后的字符串
 
}

keil的整型数溢出后继续++会怎样?

函数指针

参考教程

C语言网:函数指针及其定义和用法,C语言函数指针详解

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

/* Pointer to send function */
union interface_send_fn_u
{
    void *fun;
    uint32_t (*com_send_fn)(uint8_t *p_data, uint16_t len);
    uint32_t (*can_send_fn)(uint16_t std_id, uint8_t *p_data, uint16_t len);
};

我自己改编的示例

/
/
/USART2:
声明函数指针类型:

typedef int32_t (*can_stdmsg_rx_callback_t)(CAN_RxHeaderTypeDef *header, uint8_t *data);//相当于声明了一个函数指针类型
typedef int32_t (*uart_stdmsg_callback_t)( UART_HandleTypeDef *huart, uint8_t *data);//相当于声明了一个函数指针类型

注册头:

struct can_manage_obj
{
    CAN_HandleTypeDef *hcan;
    fifo_t tx_fifo;
    uint8_t *tx_fifo_buffer;
    uint8_t is_sending;
    can_stdmsg_rx_callback_t can_rec_callback;
};

extern struct can_manage_obj can1_manage;
//---------------------------------------------
struct uart_manage_obj
{
    UART_HandleTypeDef *huart;  
    uint8_t *Rx_Buffer;
    uint8_t *Tr_Buffer;
    uart_stdmsg_callback_t uart_rec_callback;
    uart_stdmsg_callback_t uart_tra_callback;

};

uart_manage_obj uart2_manage={
huart2;
uart2_Rx_Buffer;
uart2_Tr_Buffer;
uart2_rec_callback;
uart_tra_callback
}

extern struct uart_manage_obj uart2_manage;

//注册回调函数的函数:

/******************** Usual API ****************************/
/**
  * @brief  register can callback function.
  * @param
  * @retval error code
  */
int32_t can_fifo0_rx_callback_register(can_manage_obj_t m_obj, can_stdmsg_rx_callback_t fun)
{
    m_obj->can_rec_callback = fun;
    return E_OK;
}
int32_t uart_rx_tra_callback_register(uart_manage_obj m_obj,  UART_HandleTypeDef *huart, uint8_t *Rx_Buffer,   uint8_t *Tr_Buffer,   uart_stdmsg_callback_t fun_rec, uart_stdmsg_callback_t fun_tra)
{
	m_obj->huart=husart2;
	m_obj->Re_Buffer=Uart2_Re_Buffer;
	m_obj->Tr_Buffer=Uart2_Tr_Buffer;
    m_obj->uart_rec_callback = fun_rec;
    m_obj->uart_rec_callback = fun_tra;

    return 1;
}

uart2注册回调函数:(在board_init(); 中,与uart2_manage_init()并列)


uart_rx_tra_callback_register(&uart2_manage , husart2, Uart2_Re_Buffer, Uart2_Tr_Buffer, uart2_rec_callback,uart2_tra_callback);

uart2回调函数定义:


int32_t uart2_rec_callback(uint8_t *buf, uint32_t len)
{
    task_1();
    task_2();
    //.......
    return 1;
}

uart2配置:

void usart6_manage_init(void)
{
    usart6_manage_obj.rx_buffer = usart6_rx_buff;
    usart6_manage_obj.rx_buffer_size = USART6_RX_BUFFER_SIZE;
    usart6_manage_obj.dma_h = &hdma_usart6_rx;
    usart6_manage_obj.uart_h = &huart6;
    usart6_manage_obj.tx_fifo_buffer = usart6_tx_fifo_buff;
    usart6_manage_obj.tx_fifo_size = USART6_TX_FIFO_SIZE;
    usart6_manage_obj.tx_buffer_size = USART6_TX_BUFFER_SIZE;
    usart6_manage_obj.tx_buffer = usart6_tx_buff;
    usart6_manage_obj.is_sending = 0;

    fifo_s_init(&(usart6_manage_obj.tx_fifo), usart6_tx_fifo_buff, USART6_TX_FIFO_SIZE);

    HAL_UART_Receive_DMA(&huart6, usart6_rx_buff, USART6_RX_BUFFER_SIZE);
    __HAL_UART_ENABLE_IT(&huart6, UART_IT_IDLE);
}

//--------------------------------------------
uart2_manage_init()

尝试加入printf:

比重映射更灵活的printf方法:stdarg.h

int usart1_printf(char *fmt, ...)
{

    va_list arg;
    uint8_t buff[USART1_PRINTF_BUFF_SIZE];
    uint8_t printf_len;

    va_start(arg, fmt);
    printf_len = vsnprintf((char *)buff, USART1_PRINTF_BUFF_SIZE, fmt, arg);
    va_end(arg);

    if (printf_len > USART1_PRINTF_BUFF_SIZE)
    {
        printf_len = USART1_PRINTF_BUFF_SIZE;
    }

    usart_transmit(&usart1_manage_obj, buff, printf_len);

    return 0;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

//
/
/
/
/
/
/
/

//

typedef  int32_t(*usb_vcp_call_back_f)(uint8_t *buf, uint32_t len);
int32_t usb_vcp_rx_callback_register(usb_vcp_call_back_f fun);
int32_t usb_vcp_rx_callback_register(usb_vcp_call_back_f fun)
{
    if (usb_vcp_call_back == NULL)
    {
        usb_vcp_call_back = fun;
        return USBD_OK;
    }

    return USBD_FAIL;
}
    usb_vcp_rx_callback_register(usb_rcv_callback);
    usart1_rx_callback_register(usart1_rx_callback);
    usart6_rx_callback_register(usart6_rx_callback);
int32_t usb_rcv_callback(uint8_t *buf, uint32_t len)
{
    protocol_uart_rcv_data(USB_COM, buf, len);
    return len;
}
  • 31
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值