我正在开发一个基于 AVR ATMega32a 微控制器的项目,其中使用伺服电机从 0 度旋转到 90 度,同时捕获每个旋转度数的 ADC 值。我的目标是使伺服电机的旋转与 ADC 值捕获同步,确保在进行下一度旋转之前接收到每个旋转度数对应的 ADC 值。
背景:
微控制器:我使用的是 AVR 微控制器 ATmega32A。 MG995伺服电机:通过PWM控制伺服电机从0度到90度旋转。 ADC 配置:我已将 ADC 配置为从光电二极管传感器读取值。 连接:伺服电机和光电二极管传感器连接到微控制器。
我面临的问题是,在传输所有度数的 ADC 值之前,伺服电机似乎旋转了 90 度。理想情况下,我希望电机逐渐旋转到每一度,并等待相应的 ADC 值,然后再进入下一度。
这是我的 C 代码相关部分的简化版本:
// Function to rotate the servo to a specified degree
void RotateServo(uint16_t degree) {
OCR1A = (degree * 125) / 9 + 175; // Calculate the OCR1A value for the specified degree
_delay_ms(500); // Wait for the servo to reach the desired position
}
int main() {
...
while (1) {
for (int degree = 0; degree <= 90; degree++) {
RotateServo(degree);
// Read the ADC value from channel 0 (connected to photodiode)
adc_value = adc_read(0);
// Print the ADC value to the serial terminal
sprintf(buffer, "Degree: %d, ADC Value: %d \n", degree, adc_value);
UART_SendString(buffer);
// Wait for a moment before moving to the next degree
_delay_ms(1000);
}
_delay_ms(2000); // Wait for 2 seconds before reversing
for (int degree = 90; degree >= 0; degree--) {
RotateServo(degree);
// Read the ADC value from channel 0 (connected to photodiode)
adc_value = adc_read(0);
// Print the ADC value to the serial terminal
sprintf(buffer, "Degree: %d, ADC Value: %d \n", degree, adc_value);
UART_SendString(buffer);
// Wait for a moment before moving to the next degree
_delay_ms(1000);
}
_delay_ms(1000); // Wait for 1 second before restarting the loop
}
return 0;
}
我尝试调整伺服电机运动和 ADC 值捕获之间的延迟,但这并没有解决问题。
我的期望是实现伺服电机的同步旋转和逐度捕获ADC值,确保电机不会移动到下一个度数,直到获得当前度数的ADC值。
如果有任何见解、建议或解决方案可以帮助我解决此同步问题,我将不胜感激。谢谢您的协助。
就目前情况而言,程序中的所有内容都取决于其他内容。 UART传输和
sprintf
都非常耗时。与所有这些相比,ADC 周期非常快,更不用说到处都有大量延迟了。
因此,第一步是将所有这些从“爱好者地狱”转换为实际的实时系统,该系统可以同时执行多项操作。这意味着摆脱所有邪恶
_delay_ms
并开始使用硬件外设定时器。您应该有处理 ADC 的东西、处理伺服的东西和处理控制台/UART 的东西,这三件事不应该相互之间具有紧密耦合的时序依赖性。
每个驱动程序可以每隔 1 毫秒或某时间触发一次回调,然后决定是否该采取行动。 UART 是否可用或繁忙 - 如果繁忙,那么显然我们不应该在忙碌的等待中无所事事,而是留下计时器回调并让程序的其余部分在我们等待时做有意义的事情。与伺服和 ADC 相同。
根据 ADC 驱动程序的工作方式以及 ADC 的设置方式,它可能会返回最后读取的值,或者实际上可能忙等待轮询 ADC 完成(这也很糟糕)。有时您希望 ADC 需要手动启动来启动每次转换,而在其他情况下,您希望使用“连续转换”功能使 ADC 保持运行并重复更新其数据寄存器,然后您只需获取最新值。我不能说什么最适合您的应用。