我正在做一个涉及STM32和加速度传感器(LIS2DE)的项目 我必须每秒从传感器读取寄存器并通过 UART 将其发送到 arduino IDE,但是,不知道为什么,其他两个 HAL_I2C_Mem_Read_DMA 不起作用
我尝试删除第一个 Mem_Read,但只有第二个可以工作,所以我检查了第二个调用的返回值,它给了我 HAL_BUSY。 使用 HAL_I2C_Master_Transmit_DMA 和 HAL_I2C_Master_Receive_DMA 工作正常,但我想尝试这种方式,因为教授建议我们使用这个函数来自动执行发送+接收。 您认为单独使用“发送”和“接收”更好还是这一个更好?为什么?
另外,有没有一个函数可以获取所有3轴值?我检查了数据表,看到了自动增量功能,但我没有找到任何示例
我会留下我的代码,显然我设置了一个1秒的定时器,并为UART_TX、I2C_TX和I2C_RX设置了DMA,启用了来自UART、TIM和I2C事件的中断
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim){
HAL_I2C_Mem_Read_DMA(&hi2c1, ACCEL_ADD, OUT_X_ADD, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&acc[0], 1);
HAL_I2C_Mem_Read_DMA(&hi2c1, ACCEL_ADD, OUT_Y_ADD, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&acc[1], 1);
HAL_I2C_Mem_Read_DMA(&hi2c1, ACCEL_ADD, OUT_Z_ADD, I2C_MEMADD_SIZE_8BIT, (uint8_t*)&acc[2], 1);
}
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef* hi2c){
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
if(count==2){ //because I'll receive a single interrupt for each Mem_Read, so after the third MemRxCpltCallback will transmit thanks UART values
count = 0;
len = snprintf(string, sizeof(string), "X: %+.3fg Y: %+.3fg Z: %+.3fg\n",
acc[0] / 256.0 * 4.0,
acc[1] / 256.0 * 4.0,
acc[2] / 256.0 * 4.0);
HAL_UART_Transmit_DMA(&huart2, (unsigned char*)string, len);
}
else
count++;
}
感谢您的帮助,如果您需要更多信息或者问题中有什么不好的地方,请告诉我,我会更新问题。如果有人需要的话,我也可以发布我的代码的 zip 文件的链接
--- 更新 ---
现在我只是用 TIM IT 启动第一个,然后其他的由前一个触发,最后一个触发打印,仅使用全局变量来跟踪执行的调用。您认为这是一个相当不错的解决方案吗?它可以工作,但对我来说似乎很肮脏,但必须将 I2C 与 DMA 一起使用 顺便说一句,再次感谢您的每一份贡献
#if VERSION == 2
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim){
HAL_I2C_Mem_Read_DMA(&hi2c1, ACCEL_ADD, OUT_X_ADD, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(acc+count), 1);
count++;
}
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef* hi2c){
switch(count){
case 1:
HAL_I2C_Mem_Read_DMA(&hi2c1, ACCEL_ADD, OUT_Y_ADD, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(acc+count), 1);
count++;
break;
case 2:
HAL_I2C_Mem_Read_DMA(&hi2c1, ACCEL_ADD, OUT_Z_ADD, I2C_MEMADD_SIZE_8BIT, (uint8_t*)(acc+count), 1);
count++;
break;
case 3:
count=0;
len = snprintf(string, sizeof(string), "X: %+.3fg Y: %+.3fg Z: %+.3fg, (Tot:%+.3fg | %+.3fm/s²)\n",
acc[0] / 256.0 * 4.0,
acc[1] / 256.0 * 4.0,
acc[2] / 256.0 * 4.0,
sqrt(pow(acc[0],2)+pow(acc[1],2)+pow(acc[2],2))/64.0,
sqrt(pow(acc[0],2)+pow(acc[1],2)+pow(acc[2],2))/64.0 * 9.80665);
HAL_UART_Transmit_DMA(&huart2, (unsigned char*)string, len);
}
}
#endif
--- 更新2 --- 这是我的主要代码,其他代码是自动生成的,加上@pmacfarlane 建议的两个回调
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART2_UART_Init();
MX_I2C1_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
if (HAL_I2C_Master_Transmit_DMA(&hi2c1, ACCEL_ADD, (uint8_t*)CTRL_REG1, sizeof(CTRL_REG1)) == HAL_OK)
len = snprintf(string, sizeof(string), "LIS2DE found!\n");
else{
ACCEL_ADD = LIS2DE12_ADD;
if (HAL_I2C_Master_Transmit_DMA(&hi2c1, ACCEL_ADD, (uint8_t*)CTRL_REG1, sizeof(CTRL_REG1)) == HAL_OK)
len = snprintf(string, sizeof(string), "LIS2DE12 found!\n");
else
len = snprintf(string, sizeof(string), "Accelerator error!\n");
}
HAL_UART_Transmit_DMA(&huart2, (unsigned char*)string, len);
HAL_I2C_Master_Transmit_DMA(&hi2c1, ACCEL_ADD, (uint8_t*)CTRL_REG2, sizeof(CTRL_REG2));
HAL_I2C_Master_Transmit_DMA(&hi2c1, ACCEL_ADD, (uint8_t*)CTRL_REG4, sizeof(CTRL_REG4));
TIM2->SR &= ~TIM_SR_UIF; //or __HAL_TIM_CLEAR_IT(&htim2, TIM_IT_UPDATE); or HAL_Delay(500);
HAL_TIM_Base_Start_IT(&htim2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
#if VERSION == 3
while (!timer_elapsed){/*do nothing*/}
for (int i=0; i<3; i++){
dma_complete = false;
HAL_I2C_Mem_Read_DMA(&hi2c1, ACCEL_ADD, regs[i], I2C_MEMADD_SIZE_8BIT, (uint8_t*)(acc+i), 1);
while (!dma_complete){/*do nothing*/}
}
len = snprintf(string, sizeof(string), "X: %+.3fg Y: %+.3fg Z: %+.3fg (Tot:%+.3fg | %+.3fm/s²)\n",
acc[0] / 256.0 * 4.0,
acc[1] / 256.0 * 4.0,
acc[2] / 256.0 * 4.0,
sqrt(pow(acc[0],2)+pow(acc[1],2)+pow(acc[2],2))/64.0,
sqrt(pow(acc[0],2)+pow(acc[1],2)+pow(acc[2],2))/64.0 * 9.80665);
HAL_UART_Transmit_DMA(&huart2, (unsigned char*)string, len);
timer_elapsed = false;
#endif
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
几点:
HAL_Delay()
之类的函数将无法在计时器中断中工作,因为 sysTick 不会递增。考虑到这些要点,您可以进行类似这样的设计。 (未经测试,不完整,但希望能表明意图。)
#include <stdbool.h>
static volatile bool timer_elapsed = false;
static volatile bool dma_complete = false;
void main(void)
{
// Configure all peripherals etc.
for (;;)
{
// Wait for timer to elapse
while (!timer_elapsed)
{
// You could be doing other things while you wait...
}
// Read the three registers
for (int i = 0; i < 3; ++i)
{
static const uint8_t regs[] = {OUT_X_ADD, OUT_Y_ADD, OUT_Z_ADD};
dma_complete = false;
do_i2c_dma(regs[i]); // Call the HAL DMA function
// Wait for DMA to complete
while (!dma_complete)
{
// You could be doing things here too...
}
}
print_results(); // To be implemented
timer_elapsed = false;
}
}
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef* hi2c)
{
dma_complete = true;
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* htim)
{
timer_elapsed = true;
}
标志是易失性的,因为它们在 ISR 中被修改,否则主代码可能会认为它们永远不会改变。