ARM-F429软件调试
AD9516调试时发现通信时误码,降速后正常,推测串接的1k电阻太大了,暂时未做处理,降速运行,将寄存器写入后,AD9516运行正常,各路时钟输出均正常

程序代码编写
踩坑日志:
1、定时器中断:如果先开启HAL_TIM_Base_Start(&htimX),再开启HAL_TIM_Base_Start_IT(&htimX),那么就会导致中断无法开启,因为运行第一个函数的时候已经将状态设置为Busy,运行第二个函数时就已经无法生效了。
1. HAL_TIM_Base_Start(&htim2) 执行了什么:
- 检查状态:它首先检查
htim2.State是否等于HAL_TIM_STATE_READY。 - 锁定状态:如果准备好了,它会把状态修改为
HAL_TIM_STATE_BUSY。 - 开启硬件:设置寄存器,让定时器开始数数。
2. HAL_TIM_Base_Start_IT(&htim2) 执行了什么:
- 关键点:检查状态:它也会首先检查
htim2.State是否等于HAL_TIM_STATE_READY。 - 冲突发生:因为你先执行了
HAL_TIM_Base_Start,此时htim2.State已经是BUSY了! - 直接返回:
HAL_TIM_Base_Start_IT发现状态不是READY,它会判定“此句柄正在被占用”,然后直接返回HAL_ERROR,根本不会去设置使能中断的寄存器。
2、串口DMA发送:如果我开启DMA发送,但是发送一次就不发送了 ,原因是因为未开启串口全局中断。
HAL 库的状态机非常严谨(甚至可以说是死板)。
当你在代码里调用 HAL_UART_Transmit_DMA(&huart1, buffer, len); 时,发生了以下事情:
- HAL 库把串口的状态
huart->gState标记为HAL_UART_STATE_BUSY_TX(忙碌状态)。 - DMA 接管总线,把数据搬运给串口。
- 关键点来了:DMA 搬运完最后一个字节后,需要触发一个 DMA 传输完成中断 (DMA TC Interrupt)。
- 如果在中断里,HAL 库检测到搬运完了,它才会把串口的状态改回
HAL_UART_STATE_READY(空闲状态)。
问题就在这里:
如果你在 CubeMX 里没有勾选 DMA 的全局中断(NVIC),CPU 就永远不知道 DMA 已经发完了。
结果就是:事情虽然做完了,但状态机永远卡在 BUSY 状态。
当你第二次调用 HAL_UART_Transmit_DMA 时,HAL 库一查状态,“哇,还在忙”,于是直接返回 HAL_BUSY 并拒绝工作。
在应用层编写之前,先搭建程序调试框架,将调试部分完全独立出去,作为不影响主程序的附加部分,使用DMA进行发送,格式化信息后直接加入缓存列表,定时器定时查询列表并打印日志输出,除去内存搬运过程消耗极少CPU时间,全程DMA操作

日志输入输出函数(已测试完备):
int Log_Input(uint8_t log_Type,const char *format, ...)
{
va_list args;
uint32_t length = 0;
uint32_t timeout = 0;
RTC_TimeTypeDef sTime;
RTC_DateTypeDef sDate;
HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
switch(log_Type)
{
case Syslog: length = sprintf(Log_Message_buffer.Message_text, "[SysLog :%d,%d-%d-%02d:%02d:%02d]"
,Q_reman,sDate.Month,sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds); break;
case orderlog: length = sprintf(Log_Message_buffer.Message_text, "[taskLog:%d,%d-%d-%02d:%02d:%02d]"
,Q_reman,sDate.Month,sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds); break;
case Debuglog: length = sprintf(Log_Message_buffer.Message_text, "[Debglog:%d,%d-%d-%02d:%02d:%02d]"
,Q_reman,sDate.Month,sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds); break;
default: length = sprintf(Log_Message_buffer.Message_text, "[udeflog:%d,%d-%d-%02d:%02d:%02d]"
,Q_reman,sDate.Month,sDate.Date, sTime.Hours, sTime.Minutes, sTime.Seconds); break;
}
va_start(args, format);
length += vsnprintf((char *)Log_Message_buffer.Message_text+length, Log_Max_len, (char *)format, args);
va_end(args);
//插入缓存队列区
Log_Q.busy = 1;//占用队列
if((Log_Q.rear + 1) % Log_Queue_len == Log_Q.head) //判断缓存是否满
{
Log_Q.busy = 0;//释放队列
LED_RGB_SET_Color(Red);//指示灯变红
return -1;///
}
else
{
if(Log_Q.head == -1)
{
Log_Q.head = 0; //是否为空
}
Log_Message_buffer.Message_lenth = length;
Log_Q.rear = (Log_Q.rear + 1) % Log_Queue_len;
memcpy(&Log_Q.Log_Queue[Log_Q.rear],&Log_Message_buffer,sizeof(Log_Message_buffer));
if(Log_Q.rear >= Log_Q.head) {
Q_reman = (Log_Q.rear - Log_Q.head);
}
else{
Q_reman = (Log_Queue_len - Log_Q.head + Log_Q.rear);
}
}
Log_Q.busy = 0;//释放队列
return log_Type;
}
int Log_output_from_Queue(Log_Message_struct* out_buffer,uint16_t* len)
{
if (Log_Q.head == -1)
{
LED_RGB_SET_Color(Green);//指示灯变绿
return -1;//dbg_printf("TASK_Q empty\r\n");
}
else
{
Log_Q.head %= Log_Queue_len;
memcpy((uint8_t *)out_buffer,Log_Q.Log_Queue[Log_Q.head],Log_Max_len);
//判断队列是否为空
if (Log_Q.head == Log_Q.rear)
{
Log_Q.head = -1;
Log_Q.rear = -1;
LED_RGB_SET_Color(Green);//指示灯变绿
return 0;
}
else Log_Q.head = (Log_Q.head + 1) % Log_Queue_len;
}
LED_RGB_SET_Color(Blue);//指示灯变绿
return 1;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM1) // 确认是哪个定时器触发的
{
static int i = 0;
static int count = 0;
if (CMD_UART.gState == HAL_UART_STATE_READY) {
i = 0;
Q_empty_flag = Log_output_from_Queue(&Log_out_buffer,&Log_out_len);
if(Q_empty_flag != -1)
HAL_UART_Transmit_DMA(&CMD_UART,(uint8_t *)&Log_out_buffer.Message_text,Log_out_buffer.Message_lenth);
else return;
}
}
}
