我正在研究一个自动停车的汽车机器人,我正在使用8个(hc-sr04)超声波传感器(每侧2个),但问题是我使用的是atmega32,资源有限只有3个外部中断和3个定时器(即使使用中断以某种方式工作,我可能会遇到同时触发两个中断的风险)。
我正在使用此传感器:http://ram-e-shop.com/oscmax/catalog/product_info.php?products_id=907
我尝试过使用带有轮询程序的数字I / O引脚,但它没有用。 这是轮询程序的代码:
unsigned int read_sonar(){
int dist_in_cm = 0;
init_sonar(); // Setup pins and ports
trigger_sonar(); // send a 10us high pulse
while(!(ECHO_PIN & (1<<ECHO_BIT))){ // while echo pin is still low
USART_Message("echo pin low\r\n");
trig_counter++;
uint32_t max_response_time = SONAR_TIMEOUT;
if (trig_counter > max_response_time){ // SONAR_TIMEOUT
return TRIG_ERROR;
}
}
TCNT1=0; // reset timer
TCCR1B |= (1<<CS10); // start 16 bit timer with no prescaler
TIMSK |= (1<<TOIE1); // enable overflow interrupt on timer1
overFlowCounter=0; // reset overflow counter
sei(); // enable global interrupts
while((ECHO_PIN & (1<<ECHO_BIT))){ // while echo pin is still high
USART_Message("echo pin high\r\n");
if (((overFlowCounter*TIMER_MAX)+TCNT1) > SONAR_TIMEOUT){
USART_Message("timeout");
return ECHO_ERROR; // No echo within sonar range
}
};
TCCR1B = 0x00; // stop 16 bit timer with no prescaler
cli(); // disable global interrupts
no_of_ticks = ((overFlowCounter*TIMER_MAX)+TCNT1); // counter count
dist_in_cm = (no_of_ticks/(CONVERT_TO_CM*CYCLES_PER_US)); // distance in cm
return (dist_in_cm );}
如果我想同时读取所有传感器,这种方法不起作用,因为它会在循环中卡住一段时间。
我还尝试使用freeRTOS构建一个任务,检查每1毫秒的引脚状态,但这不会是准确的时间。
任何帮助?
答案 0 :(得分:2)
假设您使用8MHz的内部时钟,我会尝试处理这个内部定时器溢出中断,并使用整个端口连接传感器。
在正常模式或CTC模式下使用Timer(我觉得非常直观)以确保定期中断。设置适当的时间段。请记住,时钟频率非常低,所以不要夸大(我认为0.25毫秒适合)。
将传感器连接到一个端口,例如PORTB。这是一个很好的情况,因为ATmega32有4个端口,引脚编号为0-7,你使用8个传感器,因此特定端口的寄存器可以覆盖所有引脚,你可以使用一个读取来获得所有引脚的状态。
实施逻辑:
volatile uint8_t sensors_states;
volatile uint8_t read_flag = 0;
ISR(TIMER0_OVF_vect)
{
sensors_states = PORTB;
read_flag = 1;
}
int main()
{
// Initialize peripherals ...
// You must assume on your own how much time could the pin be held
// in the same state. This is important because the number must not
// be bigger than max value for the type of the array
uint8_t states_time[8] = {0, 0, 0, 0, 0, 0, 0, 0};
uint8_t prev_sensors_states = PORTB;
while(1)
{
// Wait until the flag will be set in the ISR
if(read_flag)
{
for(uint8_t i = 0, mask = 0x80 ; i < 8 ; i ++, mask >>= 1)
{
states_time[i]++;
// Compare the previous state and present state on each pin
uint8_t state = mask & sensors_states;
if((mask & prev_sensors_states) != state)
{
// Here you can use the state of the pin and the duration of that state.
// Remember that when 'state' is > 0 it means that previous state of the
// pin was '0' and if if 'state' is == 0 then the previous pin state
// was '1' (negation).
do_something_with_pin_change(states_time[i], state);
states_time[i] = 0;
}
}
// Save the previous states of the pins
prev_sensors_states = sensors_states;
// Clear the flag to await next data update
read_flag = 0;
}
}
}
如果您将尝试使用FreeRTOS您可以使用ulTaskNotifyTake
和vTaskNotifyGiveFromISR
而不是使用read_flag
来实现一个简单的机制,该机制将从中断通知任务端口已被阅读。处理器将进入空闲状态一段时间,然后您可以调用睡眠功能以最小化功耗。
我不知道您想对这些数据做什么,所以我调用了do_something_with_pin_change
函数来指示您可以使用数据的位置。
总结这个解决方案你只能使用一个中断,当然还有8个引脚。