Reputation: 43
I am working on a simple AVR C project with an ultrasonic sensor (HC-SR04) and SPI communication between the ATmega328P (Arduino) and three cascaded MAX7219 LCD matrix. The objective of the system is to detect and measure the distance using the ultrasonic sensor and display an appropriate message on the LCD matrix simultaneously.
I can perform the main functionality of both components separately. I can detect and measure distance with the HC-SR04 and I can display the text on the LCD matrix and scroll the text as well. The HC-SR04 repeatedly measures the distance roughly every 5ms.
The problem rises when I want to perform both functionalities simultaneously. What happens is that the text message is displayed repeatedly on the LCD matrix but not in full. I understand this is because I repeatedly measure the distance using the ultrasonic sensor. My guess would be interrupts, however I am not sure how to tackle this issue.
Is there a way of displaying the "last measured distance" fully on the LCD whilst still measuring distance?
The code (main parts):
// GLOBALS
volatile unsigned short echo_time;
volatile unsigned short distance;
// Text to display to LCD
char text[25] = "DEFAULT";
// Fire sensor
void fire_sensor()
{
// Fire the trigger pin
PORTD |= (1 << TRIG_PIN);
// Wait for 10 microseconds in reference to the data sheet
_delay_us(10);
// Toggle the trigger pin to turn off
PORTD &= ~(1 << TRIG_PIN);
}
// Measure distance
void measure_distance()
{
// Wait until echo pin is low and timer counter has changed
while (echo_time == 0);
// Calculate the distance in centimeters
distance = echo_time/58;
if (distance <= 60)
{
strcpy(text,"VEHICLE DETECTED");
PORTB = 0b00000001; // Turn DEBUG LED ON
}
else
{
strcpy(text,"DETECTED NOTHING");
PORTB = 0b00000000; // Turn DEBUG LED OFF
}
}
// *************************** MAIN *************************** //
int main(void)
{
// Enable interrupts
sei();
// Initialise components
EchoSetup();
SPISetup();
InitMatrix();
InitBuffer();
ClearMatrix();
// Get length of text
size_t length = strlen(text);
/* Replace with your application code */
while (1)
{
fire_sensor();
measure_distance();
_delay_ms(5);
// Display to LCD matrix character by character
for (uint16_t i = 0; i < length; i++)
{
PushCharacter(text[i] - 32);
PushBuffer(0x00); // Add empty column after character for letter spacing
}
}
}
// *************************** INTERRUPTS *************************** //
ISR(INT0_vect)
{
// ECHO is high (signal has come back) stop counter
if(PIND &(1 << PIND3)){
// Reset the counter
TCNT1 = 0;
}
else
{
// ECHO pin is low and the counter starts
echo_time = TCNT1;
}
}
Upvotes: 1
Views: 206
Reputation: 6092
I would suggest to make measure_distance() non-blocking.
// Measure distance
// (returns true if distance was process and text was updated)
bool process_distance()
{
if (echo_time == 0)
return false;
// Calculate the distance in centimeters
distance = echo_time/58;
if (distance <= 60)
{
strcpy(text,"VEHICLE DETECTED");
PORTB = 0b00000001; // Turn DEBUG LED ON
}
else
{
strcpy(text,"DETECTED NOTHING");
PORTB = 0b00000000; // Turn DEBUG LED OFF
}
echo_time = 0; // reset echo time
return true;
}
In your while loop, you no longer wait for the result to be ready but repeatedly check if it "was" ready and display the result.
while (1)
{
bool refreshDisplay = false;
fire_sensor();
refreshDisplay = process_distance();
_delay_ms(5); // Why this delay?
// Only refresh if necessary
if (refreshDisplay)
// Display to LCD matrix character by character
for (uint16_t i = 0; i < length; i++)
{
PushCharacter(text[i] - 32);
PushBuffer(0x00); // Add empty column after character for letter spacing
}
}
}
This is still not "clean code" because some responsibilities are loosely coupled between functions. But improving code like this comes with experience.
Upvotes: 1