目录
- "等待可以配置"
- uint32_t DMA_MemoryBurst;
- 问题思考:(尽量多用多说英语吧,都快忘完了)
- 哪些中断标志位是要清理的?什么时候清理?clear放函数头函数尾先后有别吗?IDLE“空闲”的准确定义是什么?DMA具体说来是怎么捣腾数据的?
- will dma clear it's memory array automaticly each call?
- the uart_dma could only receive 1 word though i write many,but been good after a whlie???
- globle_interrupt and IDLE_interrupt??
- 莫名其妙又卡到error_handler里了??
- 初步抄好了uart2,3,这次提前总的把变量名都改好再移植进去。(借助文档的ctrl.f高亮修改数字很方便!!!)
- 然后把这些变量都封装到结构体中方便watch window查看
- usart 和uart的区别?
- 连续的两个同串口HAL_UART_Transmit_DMA会导致第二个无法发送?
- 不能在中断中调用HAL_Delay()
- 21年小板串口六能发消息但不能收消息(不进中断)
- Cubemx生成代码失败——中文路径
- git 可以通过本地仓库给自己做版本控制吗?
- ?
- 串口发送的中文为什么能正确回传??
- 这是发的信息堵车了??
- 卧槽接上遥控器就给我整hard_fault??
- 想试试双缓冲区模式
- keil的整型数溢出后继续++会怎样?
- 函数指针
“等待可以配置”
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的整型数溢出后继续++会怎样?
函数指针
参考教程
/* 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;
}