免费宣传网站,宝塔ssl wordpress,自助建站seo,wordpress 打不开单片机主循环与中断资源访问冲突案例分析
在嵌入式系统中#xff0c;主循环#xff08;Main Loop#xff09;和中断服务程序#xff08;ISR#xff09;共享资源时#xff0c;如果处理不当#xff0c;会引发竞态条件#xff08;Race Condition#xff09;或数据不一致…单片机主循环与中断资源访问冲突案例分析
在嵌入式系统中主循环Main Loop和中断服务程序ISR共享资源时如果处理不当会引发竞态条件Race Condition或数据不一致问题。下面通过几个典型案例进行说明
案例1共享变量访问冲突
场景描述
主循环周期性读取传感器数据并计算平均值定时器中断每10ms更新一次传感器原始数据
冲突代码示例
uint16_t sensorData; // 共享资源// 主循环
void main(void) {uint32_t sum 0;uint8_t count 0;while(1) {sum sensorData; // ① 读取共享变量count;if(count 100) {printf(Average: %lu\n, sum / count);sum 0;count 0;}}
}// 定时器中断服务程序
void TIMER_ISR(void) {sensorData ReadSensor(); // ② 更新共享变量
}冲突原因
当主循环执行①行读取sensorData时可能被②行的中断打断若中断更新了sensorData主循环可能读取到部分更新的数据导致计算的平均值不准确
解决方案
uint16_t sensorData;
bool dataUpdated false;// 主循环
void main(void) {uint32_t sum 0;uint8_t count 0;while(1) {uint16_t localData;__disable_irq(); // 关中断if(dataUpdated) {localData sensorData;dataUpdated false;}__enable_irq(); // 开中断if(!dataUpdated) {sum localData;count;// ...}}
}// 定时器中断服务程序
void TIMER_ISR(void) {sensorData ReadSensor();dataUpdated true;
}案例2缓冲区访问冲突
场景描述
主循环处理串口接收缓冲区数据串口中断将接收到的字节存入缓冲区
冲突代码示例
#define BUFFER_SIZE 16
uint8_t rxBuffer[BUFFER_SIZE];
uint8_t bufferHead 0;
uint8_t bufferTail 0;// 主循环
void main(void) {while(1) {if(bufferHead ! bufferTail) { // ① 检查缓冲区是否有数据uint8_t data rxBuffer[bufferTail]; // ② 读取数据bufferTail (bufferTail 1) % BUFFER_SIZE; // ③ 更新尾指针ProcessData(data);}}
}// 串口接收中断
void UART_RX_ISR(void) {uint8_t data UART_Read();rxBuffer[bufferHead] data; // ④ 写入数据bufferHead (bufferHead 1) % BUFFER_SIZE; // ⑤ 更新头指针
}冲突原因
当主循环执行①-③行操作时可能被④-⑤行的中断打断若中断更新了bufferHead主循环可能误判缓冲区状态导致数据丢失或缓冲区溢出
解决方案
#define BUFFER_SIZE 16
uint8_t rxBuffer[BUFFER_SIZE];
uint8_t bufferHead 0;
uint8_t bufferTail 0;// 主循环
void main(void) {while(1) {uint8_t localHead;__disable_irq();localHead bufferHead;__enable_irq();if(localHead ! bufferTail) {uint8_t data rxBuffer[bufferTail];__disable_irq();bufferTail (bufferTail 1) % BUFFER_SIZE;__enable_irq();ProcessData(data);}}
}// 串口接收中断
void UART_RX_ISR(void) {uint8_t data UART_Read();uint8_t nextHead (bufferHead 1) % BUFFER_SIZE;if(nextHead ! bufferTail) { // 检查缓冲区是否已满rxBuffer[bufferHead] data;bufferHead nextHead;} else {HandleBufferOverflow();}
}案例3外设操作冲突
场景描述
主循环配置SPI接口并发送数据到Flash定时器中断周期性采集ADC数据并通过SPI发送到外部设备
冲突代码示例
// 主循环
void main(void) {while(1) {SPI_Configure(SPI_MODE_FLASH); // ① 配置SPI为Flash模式SPI_Write(flashData, FLASH_SIZE); // ② 发送数据到Flash// ...}
}// 定时器中断
void TIMER_ISR(void) {uint16_t adcData ADC_Read();SPI_Configure(SPI_MODE_SENSOR); // ③ 配置SPI为传感器模式SPI_Write(adcData, 2); // ④ 发送ADC数据
}冲突原因
主循环执行①-②行时可能被③-④行的中断打断中断修改了SPI配置导致主循环发送的数据格式错误造成Flash写入失败或数据传输错误
解决方案
bool spiBusy false;// 主循环
void main(void) {while(1) {if(!spiBusy) {spiBusy true;SPI_Configure(SPI_MODE_FLASH);SPI_Write(flashData, FLASH_SIZE);spiBusy false;}}
}// 定时器中断
void TIMER_ISR(void) {if(!spiBusy) {uint16_t adcData ADC_Read();spiBusy true;SPI_Configure(SPI_MODE_SENSOR);SPI_Write(adcData, 2);spiBusy false;}
}冲突预防原则
最小化临界区只在访问共享资源的短时间内关中断使用原子操作对标志位等简单变量使用原子操作资源状态管理使用标志位标记资源是否正在使用中断优先级控制关键任务使用更高优先级中断数据复制中断中只进行数据采集处理放到主循环
通过合理的资源管理和同步机制可以有效避免主循环与中断之间的冲突。