Lab 6
Lab 6
Lab. 6
Communication Protocols-Serial Peripheral Interface and
Matrix Keypad Interfacing
Objectives:
Figure 2
bit no. 7 6 5 4 3 2 1 0
seg. no. dp a b c d e f g
*********************************************************/
char codes[16] = {0x7E,0x30,0x6D,0x79,0x33,0x5B,0x5F,0x70
,0x7F,0x7B,0x77,0x1F,0x4E,0x3D,0x4F,0x47};
//function to transfer 16-bit packet to MAX7219 with MSB-first void
MAX7219_packet_write(char reg, char val){
Page 3 of 14
UINT packet;
char i;
gpio_set_level(LOAD, 0); //LOAD line is low
packet = ((((unsigned int)reg)<<8) | (unsigned int)val);
for(i=0; i<16; i++){
if(packet&(0x8000>>i)){
gpio_set_level(D_IN, 1);
gpio_set_level(CLK, 1);
gpio_set_level(CLK, 0);
} //end if else{
gpio_set_level(D_IN, 0);
gpio_set_level(CLK, 1);
gpio_set_level(CLK, 0);
} //end else} //end for //LOAD line is high to latch data
gpio_set_level(LOAD, 1);
gpio_set_level(LOAD, 0);} //end MAX7219_packet_write
//function configures MAX7219 for normal operation void
MAX7219_Config(){
gpio_set_direction(D_IN, GPIO_MODE_OUTPUT);
gpio_set_direction(LOAD, GPIO_MODE_OUTPUT);
gpio_set_direction(CLK, GPIO_MODE_OUTPUT);
gpio_set_level(CLK, 0); gpio_set_level(LOAD, 0);
//set normal operation AX7219_packet_write(SHUT_DOWN,1);
//set normal operation MAX7219_packet_write(DISPLAY_TEST,0);
//set no decode MAX7219_packet_write(DECODE,0x00);
//set intensity value MAX7219_packet_write(INTENS,INTENS_VAL);
/set number of digits scanned MAX7219_packet_write(SCAN_LIMIT,SCAN_DIGITS-1);
} //end MAX7219_Config //function to send number to display void NumOut(USHORT
num){ USHORT temp, d0, d1, d2, d3;
temp = num;
d0 = temp%10; //extract unit digit temp
= temp/10; d1 = temp%10; //extract 10th digit temp
= temp/10; d2 = temp%10; //extract 100th digit
d3 = temp/10; //extract 1000th digit
MAX7219_packet_write(DIG0,codes[d0]);
MAX7219_packet_write(DIG1,codes[d1]);
MAX7219_packet_write(DIG2,codes[d2]);
MAX7219_packet_write(DIG3,codes[d3]);
} //end NumOut
/***************************************************************************/
void app_main() {UINT NUM = 0;n MAX7219_Config();
MAX7219_packet_write(DISPLAY_TEST,1); delay_ms(1000);
MAX7219_Config(); for(;;){ NumOut(NUM++); delay_ms(50); }}
Task 1:
Make changes in Program 1 such that it displays a 4-digit random number (ranging from 0000
to 9999) after interval of one second.
Construct the circuit on breadboard and show the output to the lab instructor. Follow the safety
instructions while demonstrating the task.
code:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_system.h" // Required for random number generation
#define CLK 18 // CLK line of MAX7219
#define LOAD 19 // LOAD line of MAX7219
Page 4 of 14
Task 2:
Make changes in Program 1 such that it displays counting from 0 to 999 on digits 0 to 2 (first
3 digits on right side) and from 999 to 0 on digits 5 to 7 (last 3 digits on left side). The two
digits in the middle (digit 3 and digit 4) should remain off. Count should be updated after
interval of 100 ms. Construct the circuit on breadboard and show the output to the lab
instructor. Follow the safety instructions while demonstrating the task
code:
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#define CLK 18 // CLK line of MAX7219
#define LOAD 19 // LOAD line of MAX7219
#define D_IN 21 // DIN line of MAX7219
#define SCAN_DIGITS 8 // Number of digits to scan
#define INTENS_VAL 0x0F // Intensity of display
#define OFF 0x00 // Code to turn off digits #define DIG0 0x01
#define DIG1 0x02
#define DIG2 0x03
#define DIG3 0x04
#define DIG4 0x05
#define DIG5 0x06
#define DIG6 0x07
#define DIG7 0x08
#define DECODE 0x09
#define INTENS 0x0A
#define SCAN_LIMIT 0x0B
#define SHUT_DOWN 0x0C
#define DISPLAY_TEST 0x0F
typedef unsigned char UCHAR;
typedef unsigned int UINT;
typedef unsigned short USHORT;
void delay_ms(UINT ms) {
vTaskDelay(pdMS_TO_TICKS(ms));
}.
bit no. 7 6 5 4 3 2 1 0
seg. no. dp a b c d e f g
*********************************************************/
char codes[16] = {
0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70,
0x7F, 0x7B, 0x77, 0x1F, 0x4E, 0x3D, 0x4F, 0x47
};
void MAX7219_packet_write(char reg, char val) {
UINT packet;
char i; gpio_set_level(LOAD, 0); // LOAD line is low
packet = ((((unsigned int)reg) << 8) | (unsigned int)val); for (i = 0; i < 16; i++) {
if (packet & (0x8000 >> i)) { gpio_set_level(D_IN, 1);
gpio_set_level(CLK, 1);
gpio_set_level(CLK, 0);
} else { gpio_set_level(D_IN, 0);
gpio_set_level(CLK, 1);
gpio_set_level(CLK, 0);
}} gpio_set_level(LOAD, 1);
Page 6 of 14
gpio_set_level(LOAD, 0);
}
void MAX7219_Config() {
gpio_set_direction(D_IN, GPIO_MODE_OUTPUT);
gpio_set_direction(LOAD, GPIO_MODE_OUTPUT);
gpio_set_direction(CLK, GPIO_MODE_OUTPUT);
gpio_set_level(CLK, 0);
gpio_set_level(LOAD, 0);
MAX7219_packet_write(SHUT_DOWN, 1); MAX7219_packet_write(DISPLAY_TEST,
0); MAX7219_packet_write(DECODE, 0x00);
MAX7219_packet_write(INTENS, INTENS_VAL);
MAX7219_packet_write(SCAN_LIMIT, SCAN_DIGITS - 1);))
void DisplayNumberOnDigits(USHORT num, UCHAR digit_start) {
USHORT temp, d0, d1, d2;
temp = num;
d0 = temp % 10; // Extract unit digit
temp = temp / 10;
d1 = temp % 10; // Extract 10th digit
temp = temp / 10;
d2 = temp % 10; // Extract 100th digit
MAX7219_packet_write(digit_start, codes[d0]);
MAX7219_packet_write(digit_start + 1, codes[d1]);
MAX7219_packet_write(digit_start + 2, codes[d2]);
}
void app_main() {USHORT count_up = 0; USHORT count_down = 999; MAX7219_Config();
while (1) { DisplayNumberOnDigits(count_up, DIG0);
MAX7219_packet_write(DIG3, OFF);
MAX7219_packet_write(DIG4, OFF);
DisplayNumberOnDigits(count_down, DIG5);
count_up = (count_up + 1) % 1000; // Increment and reset at 1000
count_down = (count_down == 0) ? 999 : count_down - 1; // Decrement and reset at 0
delay_ms(100); }}
➢ Matrix Keypad
A matrix keypad is an input device that can be used to input data to a processing device such
as an MCU. A matrix keypad is arranged in the form of a pushbutton grid that are organized in
rows and columns. Each pushbutton behaves as a simple pushbutton that can be configured as
either pulled-up or pulled-down. In order to scan a keypad to identify any key pressed, all the
columns are pulled-up and rows are scanned one by one by providing logic 0 on one row at a
time. The other condition is also possible when all the rows are pulled-up and columns are
scanned one by one by providing logic 0 on one column at a time.
A 4x3 (4 rows and 3 columns) matrix keypad is shown in figure 3.
Page 7 of 14
Program 2: This program interfaces a 4x3 matrix keypad with ESP32 MCU board. The key
input by the keypad is displayed on an I2C LCD.
➢ Make ‘include.c’ file that contains the following text.
This file contains the dependencies needed for interfacing keypad and PCF8574 I2C LCD.
Copy this file in the designated folder (refer to Lab 5).
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h" #include "PCF8574_LCD.c" #include "KP4x3_ESP32.c" ➢ Place the
PCF8574_LCD.c file designated folder (refer to Lab 5).
➢ Make ‘KP4x3_ESP32.c’ file that contains the following code.
This file defines the functions and variables required for keypad scanning and key reading.
/***********************************************************************
This file defines the functions that scan a 4x3 matrix keypad and return the ASCII of that key.
CPU: ESP32 Written By: Engr. Usman Rafique Dated: Nov. 05, 2024
***********************************************************************/ //
Define GPIO pins for rows and columns
#define R0 GPIO_NUM_13
#define R1 GPIO_NUM_12
#define R2 GPIO_NUM_14
#define R3 GPIO_NUM_27 #define C0 GPIO_NUM_26 #define C1 GPIO_NUM_25
#define C2 GPIO_NUM_33 #define KP_Delay 10 //keypad key press delay in milliseconds //
4x3 Keypad layout
char keys[4][3] = { {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'}, {'*', '0', '#'} }; // Initialize GPIOs void
Keypad_Config() { // Set rows as output and columns as input
esp_rom_gpio_pad_select_gpio(R0); esp_rom_gpio_pad_select_gpio(R1);
esp_rom_gpio_pad_select_gpio(R2); esp_rom_gpio_pad_select_gpio(R3);
esp_rom_gpio_pad_select_gpio(C0); esp_rom_gpio_pad_select_gpio(C1);
esp_rom_gpio_pad_select_gpio(C2); gpio_set_direction(R0, GPIO_MODE_OUTPUT);
gpio_set_direction(R1, GPIO_MODE_OUTPUT); gpio_set_direction(R2,
GPIO_MODE_OUTPUT); gpio_set_direction(R3, GPIO_MODE_OUTPUT); // Default high
gpio_set_level(R0, 1); gpio_set_level(R1, 1); gpio_set_level(R2, 1); gpio_set_level(R3, 1);
gpio_set_direction(C0, GPIO_MODE_INPUT); gpio_set_direction(C1,
GPIO_MODE_INPUT); gpio_set_direction(C2, GPIO_MODE_INPUT); // Enable pull-up
resistors gpio_pullup_en(C0); gpio_pullup_en(C1); gpio_pullup_en(C2); } // Function to scan
the keypad and return the key char keypad_get_key() { char c0, c1, c2; //scan row0 only
gpio_set_level(R0, 0); gpio_set_level(R1, 1); gpio_set_level(R2, 1); gpio_set_level(R3, 1); c0
= gpio_get_level(C0); c1 = gpio_get_level(C1); c2 = gpio_get_level(C2); if(c0==0 && c1==1
&& c2==1) return(keys[0][0]); else if(c0==1 && c1==0 && c2==1) return(keys[0][1]); else
if(c0==1 && c1==1 && c2==0) return(keys[0][2]); //scan row1 only gpio_set_level(R0, 1);
gpio_set_level(R1, 0); gpio_set_level(R2, 1); gpio_set_level(R3, 1); c0 = gpio_get_level(C0);
c1 = gpio_get_level(C1); c2 = gpio_get_level(C2); if(c0==0 && c1==1 && c2==1)
return(keys[1][0]); else if(c0==1 && c1==0 && c2==1) return(keys[1][1]); else if(c0==1 &&
c1==1 && c2==0) return(keys[1][2]); //scan row2 only gpio_set_level(R0, 1);
gpio_set_level(R1, 1); gpio_set_level(R2, 0); gpio_set_level(R3, 1); c0 = gpio_get_level(C0);
c1 = gpio_get_level(C1); c2 = gpio_get_level(C2); if(c0==0 && c1==1 && c2==1)
return(keys[2][0]); else if(c0==1 && c1==0 && c2==1) return(keys[2][1]); else if(c0==1 &&
c1==1 && c2==0) return(keys[2][2]); //scan row3 only gpio_set_level(R0, 1);
gpio_set_level(R1, 1); gpio_set_level(R2, 1); gpio_set_level(R3, 0); c0 = gpio_get_level(C0);
c1 = gpio_get_level(C1); c2 = gpio_get_level(C2); if(c0==0 && c1==1 && c2==1)
return(keys[3][0]); else if(c0==1 && c1==0 && c2==1) return(keys[3][1]); else if(c0==1 &&
c1==1 && c2==0) return(keys[3][2]); //this must be the very last statement else return '\0'; //
Return null if no key is pressed } // Task to display key presses char Keypad_Read() { char key
= '\0'; while (key == '\0') { key = keypad_get_key(); }
vTaskDelay(pdMS_TO_TICKS(KP_Delay)); return key; } ➢ Copy the following code in
Page 8 of 14
main.c. Run the code and show the output to the lab instructor. #include "include.c" #define
LED GPIO_NUM_2 // Delay for milliseconds void delay_ms(unsigned int ms){
vTaskDelay(pdMS_TO_TICKS(ms)); }
/***************************************************************************
***/ void app_main() { char buff[20]; char num; gpio_set_direction(LED,
GPIO_MODE_OUTPUT); for(int j=0; j<6; j++){ gpio_set_level(LED, 1); delay_ms(50);
gpio_set_level(LED, 0); delay_ms(50); } PCF8574_LCD_init(); Keypad_Config();
cursor_position(0,5); lcd_print("Start"); cursor_position(1,5); lcd_print("ESP32");
delay_ms(1000); lcd_command(0x01); // clear display cursor_position(0,1); lcd_print("Key
pressed:"); for(;;){ num = Keypad_Read(); sprintf(buff,"%c ", num); cursor_position(1,7);
lcd_print(buff);
}
}
Lab Task 1:
Construct an embedded system (ES) using ESP32 that reads a temperature threshold value from
keypad and controls an LED. A matrix keypad is used to read numbers. The required ES also
has an RTC (DS1307) and an LM35 centigrade temperature sensor for measuring ambient
temperature. Time and ambient temperature are to be displayed on a MAX7219 LED display
stick. LED display should show the time in hours, minutes and seconds, separated with ‘-’ sign.
There should be a pushbutton that, when pressed, shows the current temperature on display.
When temperature exceeds the threshold, on-board LED turn on until it falls below the
threshold. Temperature threshold is to be read from the keypad when ES is powered up.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "PCF8574_LCD.c"
#include "KP4x3_ESP32.c"
#include "DS1307.c" // RTC Driver
#include "LM35.c" // LM35 Driver
#define LED GPIO_NUM_2
#define BUTTON GPIO_NUM_15
void system_init() {
gpio_set_direction(LED, GPIO_MODE_OUTPUT);
gpio_set_direction(BUTTON, GPIO_MODE_INPUT);
gpio_pullup_en(BUTTON); // Enable pull-up for button
PCF8574_LCD_init(); // Initialize LCD
Keypad_Config(); // Initialize keypad
DS1307_Init(); // Initialize RTC
LM35_Init(); // Initialize LM35
}int threshold = 0; int mode = 0; // 0: Display time, 1: Display temperature
Page 9 of 14
system_init();
button_init();
threshold = read_threshold_from_keypad();
// Main loop
while (1) {
float current_temp = LM35_ReadTemperature();
// Check threshold
if (current_temp > threshold) {
gpio_set_level(LED, 1); // Turn LED ON
} else {
gpio_set_level(LED, 0); // Turn LED OFF
}