Debugging Material for Day 2 (Released on 3 July 2024)
This material is designed as supplementary to the Day 2 Slides. You should not use this material without first reading the slides and trying out by yourself. Instead, refer to this material only if you encounter issues or bugs while following the slides.
LED Task
Blink once in two seconds
This code is from Prof's slides. We implemented the LED connecting to GND and Pin 13 on Arduino to replicate the expected performace.
Blink once in two seconds
#defineLED_PIN13voidsetup(){pinMode(LED_PIN, OUTPUT);}voidloop(){ // turn the LED on (HIGH is the voltage level)digitalWrite(LED_PIN, HIGH);delay(1000); // Wait for 1000 millisecond(s) // turn the LED off by making the voltage LOWdigitalWrite(LED_PIN, LOW);delay(1000); // Wait for 1000 millisecond(s)}
Blink twice in a second
To make the LED blink twice in a second, you need to change the delay times to 250 milliseconds. This will ensure that the LED turns on and off twice within one second. Here's the modified code:
Blink twice in a second
#defineLED_PIN13voidsetup(){pinMode(LED_PIN, OUTPUT);}voidloop(){ // turn the LED on (HIGH is the voltage level)digitalWrite(LED_PIN, HIGH);delay(250); // Wait for 250 millisecond(s) // turn the LED off by making the voltage LOWdigitalWrite(LED_PIN, LOW);delay(250); // Wait for 250 millisecond(s)}
Blink short-short-long
To make the LED blink in a short-short-long pattern, you can define the short and long delay times and sequence the blinks accordingly. Here's how you can achieve this:
Blink short-short-long
#defineLED_PIN13voidsetup(){pinMode(LED_PIN, OUTPUT);}voidloop(){ // Short blinkdigitalWrite(LED_PIN, HIGH);delay(250); // LED on for 250 millisecondsdigitalWrite(LED_PIN, LOW);delay(250); // LED off for 250 milliseconds // Another short blinkdigitalWrite(LED_PIN, HIGH);delay(250); // LED on for 250 millisecondsdigitalWrite(LED_PIN, LOW);delay(250); // LED off for 250 milliseconds // Long blinkdigitalWrite(LED_PIN, HIGH);delay(1000); // LED on for 1000 milliseconds (1 second)digitalWrite(LED_PIN, LOW);delay(1000); // LED off for 1000 milliseconds (1 second) // Pause before repeating the sequencedelay(1000); // Pause for 1 second before repeating the pattern}
In this code:
A short blink is achieved with 250 milliseconds on and 250 milliseconds off.
A long blink is achieved with 1000 milliseconds on and 1000 milliseconds off.
A 1-second pause is added after the pattern to make it more distinguishable before it repeats.
Blink randomly
To make the LED blink randomly, you can use the random() function in Arduino to generate random delay times. Here's an example code:
Blink randomly
#defineLED_PIN13voidsetup(){pinMode(LED_PIN, OUTPUT);randomSeed(analogRead(0)); // Seed the random number generator}voidloop(){ // turn the LED on (HIGH is the voltage level)digitalWrite(LED_PIN, HIGH);int onTime =random(100,1000); // Random on time between 100 and 1000 millisecondsdelay(onTime); // turn the LED off by making the voltage LOWdigitalWrite(LED_PIN, LOW);int offTime =random(100,1000); // Random off time between 100 and 1000 millisecondsdelay(offTime);}
In this code:
randomSeed(analogRead(0)) initializes the random number generator with a seed value based on an analog read from pin 0, which helps to ensure the randomness each time the Arduino is reset.
random(100, 1000) generates a random delay time between 100 and 1000 milliseconds for both the on and off states of the LED. You can adjust the range of the random values to fit your needs.
Serial Communication
we will explore serial communication with Arduino and how to improve the readability of the received data for our human users. We'll start with a basic code example and then discuss enhancements.
Basic Serial Communication Code
Here's the initial code for serial communication:
Serial Code (Basic)
voidsetup() { // put your setup code here, to run once:Serial.begin(9600);Serial.println("Hello World!\n");}voidloop() { // put your main code here, to run repeatedly:if (Serial.available()){int inByte =Serial.read();Serial.print("Read: ");Serial.print(inByte);Serial.print(" 0x");Serial.println(inByte, HEX); }}
This code sets up serial communication at a baud rate of 9600 and prints "Hello World!" when the program starts. In the loop() function, it checks if there is any data available to read from the serial buffer. If there is, it reads the incoming byte and prints it in both decimal and hexadecimal formats.
Explanation and Issue
When using Serial.read(), the function reads incoming serial data as bytes. This means the data is represented as integer values, which might not be human-readable, especially when dealing with characters.
For example, if you send the character 'A' through the serial monitor, the program will output:
Read: 65 0x41
While 65 and 0x41 (hexadecimal representation) are correct according to the ASCII standard, they are not immediately intuitive. We often want to see the actual character being sent for better understanding and debugging.
Improving Readability
To make the data more human-readable, we can modify the code to print the character representation directly. Here is the improved version:
Serial Code (Improved)
voidsetup() { // put your setup code here, to run once:Serial.begin(9600);Serial.println("Hello World!\n");}voidloop() { // put your main code here, to run repeatedly:if (Serial.available()){int inByte =Serial.read();Serial.print("Read: ");Serial.print(inByte);Serial.print(" (");Serial.print((char)inByte);Serial.print(") 0x");Serial.println(inByte, HEX); }}
Enhanced Explanation
In this improved version, we added Serial.print((char)inByte) to print the character representation of the incoming byte. Now, when a character like 'A' is sent, the output will be more informative:
Include the ZIP library in Arduino IDE: Sketch > Include Library > Add.ZIP Libraries
Here is the code in your hands out, after including the headfiles, the code can be compiled correctly.
With Library
#include<NewPing.h>#defineTRIGGER_PIN13 // Arduino pin tied to trigger pin on the ultrasonic sensor.#defineECHO_PIN12 // Arduino pin tied to echo pin on the ultrasonic sensor.#defineMAX_DISTANCE200 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.NewPingsonar(TRIGGER_PIN,ECHO_PIN,MAX_DISTANCE); // NewPing setup of pins and maximum distance.voidsetup() {Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.}voidloop() {delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.Serial.print("Ping: ");Serial.print(sonar.ping_cm()); // Send ping, get distance in cm and print result (0 = outside set distance range)Serial.println("cm");}
DC Motor
LED Blinky
Blink_PWM.ino
int ledPin =9; // LED connected to digital pin 9int brightness =0; // Initial brightnessint fadeAmount =15; // Amount to change the brightnessvoidsetup() {pinMode(ledPin, OUTPUT); // Set ledPin as an output}voidloop() {analogWrite(ledPin, brightness); // Set the brightness using PWM brightness = brightness + fadeAmount; // Increase brightness // Reverse the direction of the brightness changeif (brightness <=0|| brightness >=255) { fadeAmount =-fadeAmount; }delay(30); // Delay for 30 milliseconds to control the speed of the change}
Additional Challenge
Write a program to control the brightness of LED using Serial Communication:
// Define the LED pinconstint ledPin =13; // PWM pinint brightness =0;voidsetup() { // Initialize the LED pin as an outputpinMode(ledPin, OUTPUT); // Initialize serial communication at 9600 bits per secondSerial.begin(9600);Serial.println("Serial Begin!");}voidloop() { // Check if any data is available to readif (Serial.available() >0) { // Read the first incoming characterchar startChar =Serial.read(); // Check if it is a valid start character (assuming 'B' indicates the start of a brightness value)if (startChar =='B') { // Read the following integer valueint newBrightness =Serial.parseInt(); // Ensure the brightness value is within the valid range newBrightness =constrain(newBrightness,0,255); // Update the brightness and set the LED brightness brightness = newBrightness;analogWrite(ledPin, brightness); // Print the received brightness value to the Serial MonitorSerial.print("LED Brightness: ");Serial.println(brightness); } }}
This way, the brightness will only be updated when a valid input starting with 'B' is received, avoiding unintentional changes when no new data is present.
Challenge Questions
Ultrasonic & Interrupt
Can you use an interrupt to turn on an LED based on the distance measured by the ultrasonic sensor?
constint trigPin =12;constint echoPin =2; // Using pin 2 for interruptconstint ledPin1 =7;constint ledPin2 =8;constfloat thresholdDistance =100.0; // Threshold distance in cmvolatileunsignedlong pulseStart;volatileunsignedlong pulseEnd;volatilebool newMeasurement =false;voidsetup() {pinMode(trigPin, OUTPUT);pinMode(echoPin, INPUT);pinMode(ledPin1, OUTPUT);pinMode(ledPin2, OUTPUT);Serial.begin(9600); // Attach interrupt to echo pinattachInterrupt(digitalPinToInterrupt(echoPin), echoISR, CHANGE);}voidloop() {staticunsignedlong lastTriggerTime =0; // Trigger the ultrasonic sensor every 100msif (millis() - lastTriggerTime >=100) { // Trigger the ultrasonic sensordigitalWrite(trigPin, LOW);delayMicroseconds(2);digitalWrite(trigPin, HIGH);delayMicroseconds(10);digitalWrite(trigPin, LOW); lastTriggerTime =millis(); // Reset the timer }if (newMeasurement) { newMeasurement =false;unsignedlong duration = pulseEnd - pulseStart;float distance = (duration *0.0343) /2; // Print the distance to the Serial MonitorSerial.print("Distance: ");Serial.println(distance); // Update the LED state based on the measured distanceif (distance < thresholdDistance) {digitalWrite(ledPin1, HIGH);digitalWrite(ledPin2, LOW); } else {digitalWrite(ledPin1, LOW);digitalWrite(ledPin2, HIGH); } }}voidechoISR() {if (digitalRead(echoPin) == HIGH) { // Rising edge: record the start time pulseStart =micros(); } else { // Falling edge: record the end time and set flag pulseEnd =micros(); newMeasurement =true; }}