Brief:
A simple program to control (Toggle) the LED Array connected at PORTB using byte option.
Source Code:
Main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : LED Array - Byte Access
* Description : A simple program to control (Toggle) the LED Array connected at PORTB
* using byte option.
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
static void init_config(void)
{
ADCON1 = 0x0F;
LED_ARRAY = OFF;
TRISB = 0x00;
}
void main(void)
{
unsigned long i;
init_config();
while (1)
{
LED_ARRAY = 0x55;
for (i = 1000000; i--; );
LED_ARRAY = 0xAA;
for (i = 1000000; i--; );
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
#define LED_ARRAY PORTB
#define OFF 0x00
#endif
Microcontroller programming Example output:
Brief:
Source Code:
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : LED Array - Bit Access
* Description : A simple program to control (Toggle) a LED connected at RBO of PORTB
* Tools : Compiler - xc8 (V1.36 Light Mode)
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
static void init_config(void)
{
ADCON1 = 0x0F;
LED1 = OFF;
TRISB0 = 0;
}
void main(void)
{
unsigned long i;
init_config();
while (1)
{
LED1 = ON;
for (i = 1000000; i--; );
LED1 = OFF;
for (i = 1000000; i--; );
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
#define LED1 RB0
#define ON 1
#define OFF 0
#endif
#endif
Microcontrollers programming Example output:
Brief:
Source Code:
digital_keypad.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : digital_keypad.c
* Title : Digital Keypad - Level Triggering
* Description : A digital keypad module providing both level and edge triggering
* functions
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "digital_keypad.h"
void init_digital_keypad(void)
{
TRISC = TRISC | INPUT_PINS;
}
unsigned char read_digital_keypad(unsigned char detection_type)
{
static unsigned char once = 1;
if (detection_type == STATE_CHANGE)
{
if (((KEY_PORT & INPUT_PINS) != ALL_RELEASED) && once)
{
once = 0;
return (KEY_PORT & INPUT_PINS);
}
else if ((KEY_PORT & INPUT_PINS) == ALL_RELEASED)
{
once = 1;
}
}
else if (detection_type == LEVEL)
{
return (KEY_PORT & INPUT_PINS);
}
return 0xFF;
}
digital_keypad.h
#ifndef DIGITAL_KEYPAD_H
#define DIGITAL_KEYPAD_H
#define LEVEL 0
#define STATE_CHANGE 1
#define SWITCH1 0x0E
#define SWITCH2 0x0D
#define SWITCH3 0x0B
#define SWITCH4 0x07
#define ALL_RELEASED 0x0F
#define INPUT_PINS 0x0F
#define KEY_PORT PORTC
void init_digital_keypad(void);
unsigned char read_digital_keypad(unsigned char detection_type);
#endif
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : Digital Keypad - Level Detection
* Description : An example code to demonstarte the digital keypad using tactile keys.
* The example demonstrates level trigged operation
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "digital_keypad.h"
void glow_on_press(unsigned char key)
{
if (key == SWITCH1)
{
LED1 = ON;
}
else
{
LED1 = OFF;
}
}
static void init_config(void)
{
ADCON1 = 0x0F;
LED1 = OFF;
TRISB0 = 0;
init_digital_keypad();
}
void main(void)
{
unsigned char key;
init_config();
while (1)
{
key = read_digital_keypad(LEVEL);
glow_on_press(key);
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
/* The name LED1 is based on the legend in eCee Board */
#define LED1 RB0
#define ON 1
#define OFF 0
#endif
Brief:
Source Code:
digital_keypad.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : digital_keypad.c
* Title : Digital Keypad - Level Triggering
* Description : A digital keypad module providing both level and edge triggering
* functions
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "digital_keypad.h"
void init_digital_keypad(void)
{
TRISC = TRISC | INPUT_PINS;
}
unsigned char read_digital_keypad(unsigned char detection_type)
{
static unsigned char once = 1;
if (detection_type == STATE_CHANGE)
{
if (((KEY_PORT & INPUT_PINS) != ALL_RELEASED) && once)
{
once = 0;
return (KEY_PORT & INPUT_PINS);
}
else if ((KEY_PORT & INPUT_PINS) == ALL_RELEASED)
{
once = 1;
}
}
else if (detection_type == LEVEL)
{
return (KEY_PORT & INPUT_PINS);
}
return 0xFF;
}
digital_keypad.h
#ifndef DIGITAL_KEYPAD_H
#define DIGITAL_KEYPAD_H
#define LEVEL 0
#define STATE_CHANGE 1
#define SWITCH1 0x0E
#define SWITCH2 0x0D
#define SWITCH3 0x0B
#define SWITCH4 0x07
#define ALL_RELEASED 0x0F
#define INPUT_PINS 0x0F
#define KEY_PORT PORTC
void init_digital_keypad(void);
unsigned char read_digital_keypad(unsigned char detection_type);
#endif
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : Digital Keypad - State Change Detection
* Description : An example code to demonstarte the digital keypad using tactile keys.
* The example demonstrates state change detection
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "digital_keypad.h"
void state_change_detection(unsigned char key)
{
if (key == SWITCH1)
{
LED1 = !LED1;
}
}
static void init_config(void)
{
ADCON1 = 0x0F;
LED1 = OFF;
TRISB0 = 0;
init_digital_keypad();
}
void main(void)
{
unsigned char key;
unsigned int i;
init_config();
while (1)
{
key = read_digital_keypad(STATE_CHANGE);
state_change_detection(key);
/* A delay to suppress key bounce */
for (i = 50000; i--; );
}
}
main.h
#ifndef DIGITAL_KEYPAD_H
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
/* The name LED1 is based on the legend in eCee Board */
#define LED1 RB0
#define ON 1
#define OFF 0
#endif
Brief:
Source Code:
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : Seven Segment Display
* Description : A simple program to demonstrate Seven Segment Display
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "ssd_display.h"
const unsigned char digits[] = {ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN, EIGHT, NINE};
static unsigned char ssd[MAX_SSD_CNT];
void init_config(void)
{
init_ssd_control();
}
void main(void)
{
init_config();
while (1)
{
ssd[3] = ZERO;
ssd[2] = ONE;
ssd[1] = TWO;
ssd[0] = THREE;
display(ssd);
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#endif
ssd_display.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : ssd_display.c
* Title : Seven Segment Display Driver
* Description : A module to drive Seven Segment Display
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "ssd_display.h"
void init_ssd_control(void)
{
/* Setting PORTB as output for Data Lines */
TRISD = 0x00;
/* Setting SSD Enable lines as output */
TRISA = TRISA & 0xF0;
/* Switching OFF all the SSDs to start with */
SSD_CNT_PORT = SSD_CNT_PORT & 0xF0;
}
/* Better if implemented in timer handler */
void display(unsigned char data[])
{
unsigned int wait;
unsigned char data_bit;
unsigned char digit;
for (digit = 0; digit < MAX_SSD_CNT; digit++)
{
SSD_DATA_PORT = data[digit];
SSD_CNT_PORT = (SSD_CNT_PORT & 0xF0) | (0x01 << digit);
for (wait = 1000; wait--; );
}
}
ssd_display.c
#ifndef SSD_DISPLAY_H
#define SSD_DISPLAY_H
#define MAX_SSD_CNT 4
#define HIGH 1
#define LOW 0
/* This values are for common cathode display */
#define ZERO 0xE7
#define ONE 0x21
#define TWO 0xCB
#define THREE 0x6B
#define FOUR 0x2D
#define FIVE 0x6E
#define SIX 0xEE
#define SEVEN 0x23
#define EIGHT 0xEF
#define NINE 0x6F
#define DOT 0x10
#define BLANK 0x00
/* Need to fill All others */
#define M_ONE 0x9D
#define MINUS 0xFD
#define MAX_SSD_CNT 4
#define MAX_COUNT 9
#define COUNT_ADDR 0x00
#define SSD_DATA_PORT PORTD
#define SSD_CNT_PORT PORTA
void init_ssd_control(void);
void display(unsigned char data[]);
#endif
Brief:
Source Code:
external_interrupt.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : external_interrupt.c
* Title : External Interrupt Configuration
* Description : A configuration function to detect rising edge signal
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "external_interrupt.h"
void init_external_interrupt(void)
{
INTEDG0 = 1;
INT0F = 0;
INT0E = 1;
}
external_interrupt.h
#ifndef EXTERNAL_INTERRUPT_H
#define EXTERNAL_INTERRUPT_H
void init_external_interrupt(void);
#endif
isr.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : isr.c
* Title : Interrupt Service Routine
* Description : Signal registration happens here
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "isr.h"
bit key_detected;
void interrupt isr(void)
{
if (INT0F == 1)
{
key_detected = 1;
INT0F = 0;
}
}
isr.h
#ifndef ISR_H
#define ISR_H
#endif
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : External Interrupts
* Description : A simple program to demonstarte external interrupt at INT pin
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "external_interrupt.h"
#include "isr.h"
extern bit key_detected;
static void init_config(void)
{
ADCON1 = 0x0F;
TRISB7 = 0;
TRISB0 = 1;
init_external_interrupt();
GIE = 1;
}
void main(void)
{
unsigned short wait;
init_config();
while (1)
{
if (key_detected)
{
key_detected = 0;
LED8 = !LED8;
}
for (wait = 10000; wait--; );
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
/* The name LED1 is based on the legend in eCee Board */
#define LED8 RB7
#define ON
#define OFF
#endif
Brief:
Source Code:
digital_keypad.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : digital_keypad.c
* Title : Digital Keypad - Level Triggering
* Description : A digital keypad module providing both level and edge triggering
* functions
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "digital_keypad.h"
void init_digital_keypad(void)
{
TRISC = TRISC | INPUT_PINS;
}
unsigned char read_digital_keypad(unsigned char detection_type)
{
static unsigned char once = 1;
if (detection_type == STATE_CHANGE)
{
if (((KEY_PORT & INPUT_PINS) != ALL_RELEASED) && once)
{
once = 0;
return (KEY_PORT & INPUT_PINS);
}
else if ((KEY_PORT & INPUT_PINS) == ALL_RELEASED)
{
once = 1;
}
}
else if (detection_type == LEVEL)
{
return (KEY_PORT & INPUT_PINS);
}
return 0xFF;
}
digital_keypad.h
#ifndef DIGITAL_KEYPAD_H
#define DIGITAL_KEYPAD_H
#define LEVEL 0
#define STATE_CHANGE 1
#define SWITCH1 0x0E
#define SWITCH2 0x0D
#define SWITCH3 0x0B
#define SWITCH4 0x07
#define ALL_RELEASED 0x0F
#define INPUT_PINS 0x0F
void init_digital_keypad(void);
unsigned char read_digital_keypad(unsigned char detection_type);
#endif
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : Clock I/O - PWM
* Description : A program demonstrating Software PWM (Bit Banged)
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "digital_keypad.h"
#define PERIOD 100
void software_pwm(void)
{
unsigned char key;
static unsigned short wait = 0;
static unsigned char prog_cycle;
static unsigned char duty_change = 50;
key = read_digital_keypad(LEVEL);
if (!wait--)
{
wait = 10000;
if (key == SWITCH1)
{
if (duty_change != PERIOD)
{
duty_change++;
}
}
if (key == SWITCH2)
{
if (duty_change != 0)
{
duty_change--;
}
}
}
if (prog_cycle < duty_change)
{
LED1 = ON;
}
else
{
LED1 = OFF;
}
if (prog_cycle++ == PERIOD)
{
prog_cycle = 0;
}
}
static void init_config(void)
{
ADCON1 = 0x0F;
LED1 = OFF;
TRISB0 = 0;
init_digital_keypad();
}
void main(void)
{
init_config();
while (1)
{
software_pwm();
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
#define LED1 RB0
#define KEY_PORT PORTC
#define ON 1
#define OFF 0
#endif
Brief:
Source Code:
isr.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : isr.c
* Title : Timer Module - Timer 0 ISR
* Description : An ISR code to generate 1 second timing
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
void interrupt isr(void)
{
static unsigned short count;
if (TMR0IF)
{
TMR0 = TMR0 + 8;
if (count++ == 20000)
{
count = 0;
LED1 = !LED1;
}
TMR0IF = 0;
}
}
isr.h
#ifndef ISR_H
#define ISR_H
#endif
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : Timer Module - Timer 0
* Description : A code to demonstrate the working of Timer module
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "timer0.h"
void init_config(void)
{
/* Clear old content */
PORTB = 0x00;
/* Set PORTB as a Output */
TRISB = 0x00;
/* Config PORTB as digital */
ADCON1 = 0x0F;
init_timer0();
/* Global Interrupt Enable */
GIE = 1;
}
void main(void)
{
init_config();
while (1)
{
;
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
#define LED1 RB0
#define KEY_PORT PORTC
#define ON 1
#define OFF 0
#endif
timer0.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : timer0.c
* Title : Timer Module - Timer 0 Initialiation
* Description : A initialization code to enable timer 0 module
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "timer0.h"
void init_timer0(void)
{
/*
* Setting instruction cycle clock (Fosc / 4) as the source of
* timer0
*/
T0CS = 0;
TMR0 = 6;
/* Clearing timer0 overflow interrupt flag bit */
T0IF = 0;
/* Enabling timer0 overflow interrupt */
TMR0IE = 1;
}
timer0.h
#ifndef TIMER0_H
#define TIMER0_H
void init_timer0(void);
#endif
Brief:
Source Code:
clcd.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : clcd.c
* Title : CLCD Driver
* Description : Module to make CLCD work in 8 bit mode
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "clcd.h"
void clcd_write(unsigned char byte, unsigned char control_bit)
{
CLCD_RS = control_bit;
CLCD_PORT = byte;
/* Should be atleast 200ns */
CLCD_EN = HI;
CLCD_EN = LO;
PORT_DIR = INPUT;
CLCD_RW = HI;
CLCD_RS = INSTRUCTION_COMMAND;
do
{
CLCD_EN = HI;
CLCD_EN = LO;
} while (CLCD_BUSY);
CLCD_RW = LO;
PORT_DIR = OUTPUT;
}
void init_clcd()
{
/* Set PortD as output port for CLCD data */
TRISD = 0x00;
/* Set PortC as output port for CLCD control */
TRISC = TRISC & 0xF8;
CLCD_RW = LO;
TWO_LINE_5x7_MATRIX_8_BIT;
CURSOR_HOME;
DISP_ON_AND_CURSOR_OFF;
CLEAR_DISP_SCREEN;
}
void clcd_print(const unsigned char *data, unsigned char addr)
{
clcd_write(addr, INSTRUCTION_COMMAND);
while (*data != '\0')
{
clcd_write(*data++, DATA_COMMAND);
}
}
void clcd_putch(const unsigned char data, unsigned char addr)
{
clcd_write(addr, INSTRUCTION_COMMAND);
clcd_write(data, DATA_COMMAND);
}
clcd.h
#ifndef CLCD_H
#define CLCD_H
#define HI 1
#define LO 0
#define INPUT 0xFF
#define OUTPUT 0x00
#define DATA_COMMAND 1
#define INSTRUCTION_COMMAND 0
#define LINE1(x) (0x80 + (x))
#define LINE2(x) (0xC0 + (x))
#define TWO_LINE_5x7_MATRIX_8_BIT clcd_write(0x38, INSTRUCTION_COMMAND)
#define CLEAR_DISP_SCREEN clcd_write(0x01, INSTRUCTION_COMMAND)
#define CURSOR_HOME clcd_write(0x02, INSTRUCTION_COMMAND)
#define DISP_ON_AND_CURSOR_OFF clcd_write(0x0C, INSTRUCTION_COMMAND)
#define CLCD_PORT PORTD
#define CLCD_EN RC2
#define CLCD_RS RC1
#define CLCD_RW RC0
#define CLCD_BUSY RD7
#define PORT_DIR TRISD7
void init_clcd(void);
void clcd_print(const unsigned char *data, unsigned char addr);
void clcd_putch(const unsigned char data, unsigned char addr);
void clcd_write(unsigned char bit_values, unsigned char control_bit);
#endif
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : CLCD - Character Liquid Crystal Display
* Description : A code to demonstrate the working of CLCD module
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "clcd.h"
static void init_config(void)
{
init_clcd();
}
void main(void)
{
init_config();
while (1)
{
clcd_putch('H', LINE1(0));
clcd_print("Hello", LINE2(4));
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
#define OFF 0xFF
#endif
Brief:
Source Code:
clcd.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : clcd.c
* Title : CLCD Driver
* Description : Module to make CLCD work in 8 bit mode
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "clcd.h"
void clcd_write(unsigned char byte, unsigned char control_bit)
{
CLCD_RS = control_bit;
CLCD_PORT = byte;
/* Should be atleast 200ns */
CLCD_EN = HI;
CLCD_EN = LO;
PORT_DIR = INPUT;
CLCD_RW = HI;
CLCD_RS = INSTRUCTION_COMMAND;
do
{
CLCD_EN = HI;
CLCD_EN = LO;
} while (CLCD_BUSY);
CLCD_RW = LO;
PORT_DIR = OUTPUT;
}
void init_clcd()
{
/* Set PortD as output port for CLCD data */
TRISD = 0x00;
/* Set PortC as output port for CLCD control */
TRISC = TRISC & 0xF8;
CLCD_RW = LO;
TWO_LINE_5x7_MATRIX_8_BIT;
CURSOR_HOME;
DISP_ON_AND_CURSOR_OFF;
CLEAR_DISP_SCREEN;
}
void clcd_print(const unsigned char *data, unsigned char addr)
{
clcd_write(addr, INSTRUCTION_COMMAND);
while (*data != '\0')
{
clcd_write(*data++, DATA_COMMAND);
}
}
void clcd_putch(const unsigned char data, unsigned char addr)
{
clcd_write(addr, INSTRUCTION_COMMAND);
clcd_write(data, DATA_COMMAND);
}
clcd.h
#ifndef CLCD_H
#define CLCD_H
#define HI 1
#define LO 0
#define INPUT 0xFF
#define OUTPUT 0x00
#define DATA_COMMAND 1
#define INSTRUCTION_COMMAND 0
#define LINE1(x) (0x80 + (x))
#define LINE2(x) (0xC0 + (x))
#define TWO_LINE_5x7_MATRIX_8_BIT clcd_write(0x38, INSTRUCTION_COMMAND)
#define CLEAR_DISP_SCREEN clcd_write(0x01, INSTRUCTION_COMMAND)
#define CURSOR_HOME clcd_write(0x02, INSTRUCTION_COMMAND)
#define DISP_ON_AND_CURSOR_OFF clcd_write(0x0C, INSTRUCTION_COMMAND)
#define CLCD_PORT PORTD
#define CLCD_EN RC2
#define CLCD_RS RC1
#define CLCD_RW RC0
#define CLCD_BUSY RD7
#define PORT_DIR TRISD7
void init_clcd(void);
void clcd_print(const unsigned char *data, unsigned char addr);
void clcd_putch(const unsigned char data, unsigned char addr);
void clcd_write(unsigned char bit_values, unsigned char control_bit);
#endif
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : Matrix Keypad
* Description : A simple program to demonstrate the scanning of Matrix Keypad using
* tactile switches
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "matrix_keypad.h"
#include "clcd.h"
void check_matrix_keypad(void)
{
unsigned char key;
unsigned short i;
key = read_switches(LEVEL_CHANGE);
if (key != ALL_RELEASED)
{
clcd_print("Key ", LINE2(1));
clcd_putch('0' + (key / 10), LINE2(5));
clcd_putch('0' + (key % 10), LINE2(6));
clcd_print(" Pressed ", LINE2(7));
RB0 = !RB0;
for (i = 50000; i--; );
}
else
{
//clcd_print(" No Key Pressed ", LINE2(0));
}
}
void init_config(void)
{
init_matrix_keypad();
init_clcd();
clcd_print(" Matrix Keypad ", LINE1(0));
}
void main(void)
{
init_config();
while(1)
{
check_matrix_keypad();
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
#endif
matrix_keypad.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : matrix_keypad.c
* Title : Matrix Keypad - Driver
* Description : A module which detects both level and state change of user input using
* matrix keypad
*-----------------------------------------------------------------------------------------------*/
#include "matrix_keypad.h"
#include "main.h"
void init_matrix_keypad(void)
{
/* Config PORTB as digital */
ADCON1 = 0x0F;
/* Set Rows (RB7 - RB5) as Outputs and Columns (RB4 - RB1) as Inputs */
TRISB = 0x1E;
/* Set PORTB input as pull up for columns */
RBPU = 0;
MATRIX_KEYPAD_PORT = MATRIX_KEYPAD_PORT | 0xE0;
}
unsigned char scan_key(void)
{
ROW1 = LO;
ROW2 = HI;
ROW3 = HI;
if (COL1 == LO)
{
return 1;
}
else if (COL2 == LO)
{
return 4;
}
else if (COL3 == LO)
{
return 7;
}
else if (COL4 == LO)
{
return 10;
}
ROW1 = HI;
ROW2 = LO;
ROW3 = HI;
if (COL1 == LO)
{
return 2;
}
else if (COL2 == LO)
{
return 5;
}
else if (COL3 == LO)
{
return 8;
}
else if (COL4 == LO)
{
return 11;
}
ROW1 = HI;
ROW2 = HI;
ROW3 = LO;
/* TODO: Why more than 2 times? */
ROW3 = LO;
if (COL1 == LO)
{
return 3;
}
else if (COL2 == LO)
{
return 6;
}
else if (COL3 == LO)
{
return 9;
}
else if (COL4 == LO)
{
return 12;
}
return 0xFF;
}
unsigned char read_switches(unsigned char detection_type)
{
static unsigned char once = 1;
unsigned char key;
key = scan_key();
if (detection_type == STATE_CHANGE)
{
if ((key != ALL_RELEASED) && once)
{
once = 0;
return key;
}
else if (key == ALL_RELEASED)
{
once = 1;
}
}
else if (detection_type == LEVEL_CHANGE)
{
return key;
}
return 0xFF;
}
matrix_keypad.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
#endif
Brief:
Source Code:
adc.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : adc.c
* Title : ADC Driver
* Description : Module to scan analog channel
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
void init_adc(void)
{
/* Selecting right justified ADRES Registers order */
ADFM = 1;
/*
* Acqusition time selection bits
* Set for 4 Tad
*/
ACQT2 = 0;
ACQT1 = 1;
ACQT0 = 0;
/*
* Selecting the conversion clock of Fosc / 32 -> 1.6usecs -> 1Tad
* Our device frequency is 20 MHz
*/
ADCS0 = 0;
ADCS1 = 1;
ADCS2 = 0;
/* Stop the conversion to start with */
GODONE = 0;
/* Selecting the channel */
CHS2 = 1;
/* Voltage reference bit as VSS */
VCFG1 = 0;
/* Voltage reference bit as VDD */
VCFG0 = 0;
/* Just clearing the ADRESH & ADRESL registers, for time pass */
ADRESH = 0;
ADRESL = 0;
/* Turn ON the ADC module */
ADON = 1;
}
unsigned short read_adc(unsigned char channel)
{
unsigned short reg_val;
/* Set the required channel */
ADCON0 = (ADCON0 & 0xC3) | (channel << 2);
/* Set the required pin as analog pin */
ADCON1 = (ADCON1 & 0xF0) | (0x0E - channel);
/* Start the conversion */
GO = 1;
while (GO);
reg_val = (ADRESH << 8) | ADRESL;
return reg_val;
}
adc.h
#ifndef ADC_H
#define ADC_H
#define CHANNEL0 0x00
#define CHANNEL1 0x01
#define CHANNEL2 0x02
#define CHANNEL3 0x03
#define CHANNEL4 0x04
#define CHANNEL5 0x05
#define CHANNEL6 0x06
#define CHANNEL7 0x07
#define CHANNEL8 0x08
#define CHANNEL9 0x09
#define CHANNEL10 0x0A
void init_adc(void);
unsigned short read_adc(unsigned char channel);
#endif
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : Analog to Digital Convertor
* Description : A simple program to demonstrate reading Analog Inputs
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "adc.h"
void glow_led(unsigned short adc_reg_val)
{
unsigned char i;
if (adc_reg_val > 512)
{
LED1 = ON;
}
else
{
LED1 = OFF;
}
}
static void init_config(void)
{
LED1 = OFF;
TRISB0 = 0;
init_adc();
}
void main(void)
{
unsigned short adc_reg_val;
init_config();
while (1)
{
adc_reg_val = read_adc(CHANNEL4);
glow_led(adc_reg_val);
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define ON 1
#define OFF 0
#define LED1 RB0
#endif
Brief:
Source Code:
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : Universal Asynchronus Receive Transmit
* Description : A simple program to demonstrate host and target communication
* using UART
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "uart.h"
void init_config(void)
{
init_uart();
puts("Emertxe Information Technologies. Press any key to continue\n\r");
getch();
}
void main(void)
{
init_config();
puts("Welcome. This is UART Test Code.\n\r");
puts("You should get back whatever you type:\n\r");
while (1)
{
getche();
}
}
main.h
#ifndef CLCD_H
#define CLCD_H
#define HI 1
#define LO 0
#define INPUT 0xFF
#define OUTPUT 0x00
#define DATA_COMMAND 1
#define INSTRUCTION_COMMAND 0
#define LINE1(x) (0x80 + (x))
#define LINE2(x) (0xC0 + (x))
#define TWO_LINE_5x7_MATRIX_8_BIT clcd_write(0x38, INSTRUCTION_COMMAND)
#define CLEAR_DISP_SCREEN clcd_write(0x01, INSTRUCTION_COMMAND)
#define CURSOR_HOME clcd_write(0x02, INSTRUCTION_COMMAND)
#define DISP_ON_AND_CURSOR_OFF clcd_write(0x0C, INSTRUCTION_COMMAND)
#define CLCD_PORT PORTD
#define CLCD_EN RC2
#define CLCD_RS RC1
#define CLCD_RW RC0
#define CLCD_BUSY RD7
#define PORT_DIR TRISD7
void init_clcd(void);
void clcd_print(const unsigned char *data, unsigned char addr);
void clcd_putch(const unsigned char data, unsigned char addr);
void clcd_write(unsigned char bit_values, unsigned char control_bit);
#endif
uart.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : uart.c
* Title : UART Driver
* Description : Module to drive UART peripheral
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "uart.h"
void init_uart(void)
{
/* Serial initialization */
RX_PIN = 1;
TX_PIN = 0;
/* TXSTA:- Transmitor Status and control Register */
/* Clock selection control bit */
CSRC = 0;
/* 9bit TX enable or disable bit */
TX9 = 0;
/* UART Tarsmition enable bit */
TXEN = 1;
/* Synchronous or Asynchronous mode selection */
/* Asynchronous */
SYNC = 0;
/* Send the Break character bit */
SENDB = 0;
/* Low or High baud rate selection bit */
/* High Baud Rate */
BRGH = 1;
/* Trasmiter Shift register status bit */
TRMT = 0;
/* 9th bit trasmite data */
TX9D = 0;
/* RCSTA :- Recepition Status and control Register */
/* TX/RC7 and RX/RC6 act as serial port */
SPEN = 1;
/* 9bit RX enable or disable bit */
RX9 = 0;
/* Single reception enable or disable */
SREN = 0;
/* Continous reception enable or disable */
CREN = 1;
/* Adress detection enable bit */
ADDEN = 0;
/* Frame error bit */
FERR = 0;
/* Overrun error bit */
OERR = 0;
/* 9th bit received bit */
RX9D = 0;
/* BAUDCTL:- Baud rate control register */
/* Auto baud detection overflow bit */
ABDOVF = 0;
/* Receive idle flag bit */
RCIDL = 1;
/* Synchronous clock polarity selecton bit */
SCKP = 0;
/* 16bit baud generate bit */
BRG16 = 0;
/* Wakeup enable bit */
WUE = 0;
/* Auto baud detect enable bit */
ABDEN = 0;
/* Baud Rate Setting Register */
/* Set to 10 for 115200, 64 for 19200 and 129 for 9600 */
SPBRG = 129;
/* TX interrupt enable bit */
TXIE = 1;
/* TX interrupt flag bit */
TXIF = 0;
/* RX interrupt enable bit */
RCIE = 1;
/* RX interrupt enable bit */
RCIF = 0;
}
void putch(unsigned char byte)
{
/* Output one byte */
/* Set when register is empty */
while(!TXIF)
{
continue;
}
TXREG = byte;
}
int puts(const char *s)
{
while(*s)
{
putch(*s++);
}
return 0;
}
unsigned char getch(void)
{
/* Retrieve one byte */
/* Set when register is not empty */
while(!RCIF)
{
continue;
}
return RCREG;
}
unsigned char getche(void)
{
unsigned char c;
putch(c = getch());
return (c);
}
uart.h
#ifndef SCI_H
#define SCI_H
#define RX_PIN TRISC7
#define TX_PIN TRISC6
void init_uart(void);
void putch(unsigned char byte);
int puts(const char *s);
unsigned char getch(void);
unsigned char getch_with_timeout(unsigned short max_time);
unsigned char getche(void);
#endif
Brief:
Source Code:
clcd.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : clcd.c
* Title : CLCD Driver
* Description : Module to make CLCD work in 8 bit mode
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "clcd.h"
void clcd_write(unsigned char byte, unsigned char control_bit)
{
CLCD_RS = control_bit;
CLCD_PORT = byte;
/* Should be atleast 200ns */
CLCD_EN = HI;
CLCD_EN = LO;
PORT_DIR = INPUT;
CLCD_RW = HI;
CLCD_RS = INSTRUCTION_COMMAND;
do
{
CLCD_EN = HI;
CLCD_EN = LO;
} while (CLCD_BUSY);
CLCD_RW = LO;
PORT_DIR = OUTPUT;
}
void init_clcd()
{
/* Set PortD as output port for CLCD data */
TRISD = 0x00;
/* Set PortC as output port for CLCD control */
TRISC = TRISC & 0xF8;
CLCD_RW = LO;
TWO_LINE_5x7_MATRIX_8_BIT;
CURSOR_HOME;
DISP_ON_AND_CURSOR_OFF;
CLEAR_DISP_SCREEN;
}
void clcd_print(const unsigned char *data, unsigned char addr)
{
clcd_write(addr, INSTRUCTION_COMMAND);
while (*data != '\0')
{
clcd_write(*data++, DATA_COMMAND);
}
}
void clcd_putch(const unsigned char data, unsigned char addr)
{
clcd_write(addr, INSTRUCTION_COMMAND);
clcd_write(data, DATA_COMMAND);
}
clcd.h
#ifndef CLCD_H
#define CLCD_H
#define HI 1
#define LO 0
#define INPUT 0xFF
#define OUTPUT 0x00
#define DATA_COMMAND 1
#define INSTRUCTION_COMMAND 0
#define LINE1(x) (0x80 + (x))
#define LINE2(x) (0xC0 + (x))
#define TWO_LINE_5x7_MATRIX_8_BIT clcd_write(0x38, INSTRUCTION_COMMAND)
#define CLEAR_DISP_SCREEN clcd_write(0x01, INSTRUCTION_COMMAND)
#define CURSOR_HOME clcd_write(0x02, INSTRUCTION_COMMAND)
#define DISP_ON_AND_CURSOR_OFF clcd_write(0x0C, INSTRUCTION_COMMAND)
#define CLCD_PORT PORTD
#define CLCD_EN RC2
#define CLCD_RS RC1
#define CLCD_RW RC0
#define CLCD_BUSY RD7
#define PORT_DIR TRISD7
void init_clcd(void);
void clcd_print(const unsigned char *data, unsigned char addr);
void clcd_putch(const unsigned char data, unsigned char addr);
void clcd_write(unsigned char bit_values, unsigned char control_bit);
#endif
ds1307.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : ds1307.c
* Title : DS1307 RTC Driver
* Description : Module to communicate with DS1307
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "ds1307.h"
#include "i2c.h"
/*
* DS1307 Slave address
* D0 - Write Mode
* D1 - Read Mode
*/
void init_ds1307(void)
{
unsigned char dummy;
/* Setting the CH bit of the RTC to Stop the Clock */
dummy = read_ds1307(SEC_ADDR);
write_ds1307(SEC_ADDR, dummy | 0x80);
/* Seting 12 Hr Format */
dummy = read_ds1307(HOUR_ADDR);
write_ds1307(HOUR_ADDR, dummy | 0x40);
/*
* Control Register of DS1307
* Bit 7 - OUT
* Bit 6 - 0
* Bit 5 - OSF
* Bit 4 - SQWE
* Bit 3 - 0
* Bit 2 - 0
* Bit 1 - RS1
* Bit 0 - RS0
*
* Seting RS0 and RS1 as 11 to achive SQW out at 32.768 KHz
*/
write_ds1307(CNTL_ADDR, 0x93);
/* Clearing the CH bit of the RTC to Start the Clock */
dummy = read_ds1307(SEC_ADDR);
write_ds1307(SEC_ADDR, dummy & 0x7F);
}
void write_ds1307(unsigned char address, unsigned char data)
{
i2c_start();
i2c_write(SLAVE_WRITE);
i2c_write(address);
i2c_write(data);
i2c_stop();
}
unsigned char read_ds1307(unsigned char address)
{
unsigned char data;
i2c_start();
i2c_write(SLAVE_WRITE);
i2c_write(address);
i2c_rep_start();
i2c_write(SLAVE_READ);
data = i2c_read();
i2c_stop();
return data;
}
ds1307.h
#ifndef Ds1307_H
#define Ds1307_H
#define SLAVE_READ 0xD1
#define SLAVE_WRITE 0xD0
#define SEC_ADDR 0x00
#define MIN_ADDR 0x01
#define HOUR_ADDR 0x02
#define DAY_ADDR 0x03
#define DATE_ADDR 0x04
#define MONTH_ADDR 0x05
#define YEAR_ADDR 0x06
#define CNTL_ADDR 0x07
void init_ds1307(void);
void write_ds1307(unsigned char address1, unsigned char data);
unsigned char read_ds1307(unsigned char address1);
#endif
i2c.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : i2c.c
* Title : I2C Driver
* Description : Module containing the I2C driver function
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
void init_i2c(void)
{
/* Set SCL and SDA pins as inputs */
TRISC3 = 1;
TRISC4 = 1;
/* Set I2C master mode */
SSPCON1 = 0x28;
SSPADD = 0x30;
/* Use I2C levels, worked also with '0' */
CKE = 0;
/* Disable slew rate control worked also with '0' */
SMP = 1;
/* Clear SSPIF interrupt flag */
SSPIF = 0;
/* Clear bus collision flag */
BCLIF = 0;
}
void i2c_idle(void)
{
while (!SSPIF);
SSPIF = 0;
}
void i2c_ack(void)
{
if (ACKSTAT)
{
/* Do debug print here if required */
}
}
void i2c_start(void)
{
SEN = 1;
i2c_idle();
}
void i2c_stop(void)
{
PEN = 1;
i2c_idle();
}
void i2c_rep_start(void)
{
RSEN = 1;
i2c_idle();
}
void i2c_write(unsigned char data)
{
SSPBUF = data;
i2c_idle();
}
void i2c_rx_mode(void)
{
RCEN = 1;
i2c_idle();
}
void i2c_no_ack(void)
{
ACKDT = 1;
ACKEN = 1;
}
unsigned char i2c_read(void)
{
i2c_rx_mode();
i2c_no_ack();
return SSPBUF;
}
i2c.h
#ifndef I2C_H
#define I2C_H
void init_i2c(void);
void i2c_start(void);
void i2c_rep_start(void);
void i2c_stop(void);
void i2c_write(unsigned char data);
unsigned char i2c_read(void);
#endif
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : DS1307 RTC
* Description : An application to intract with DS1307 RTC using I2C protocol
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "clcd.h"
#include "ds1307.h"
#include "i2c.h"
unsigned char clock_reg[3];
unsigned char calender_reg[4];
unsigned char time[9];
unsigned char date[11];
void display_date(void)
{
clcd_print(date, LINE2(3));
}
void display_time(void)
{
clcd_print(time, LINE2(2));
if (clock_reg[0] & 0x40)
{
if (clock_reg[0] & 0x20)
{
clcd_print("PM", LINE2(12));
}
else
{
clcd_print("AM", LINE2(12));
}
}
}
static void get_time(void)
{
clock_reg[0] = read_ds1307(HOUR_ADDR);
clock_reg[1] = read_ds1307(MIN_ADDR);
clock_reg[2] = read_ds1307(SEC_ADDR);
if (clock_reg[0] & 0x40)
{
time[0] = '0' + ((clock_reg[0] >> 4) & 0x01);
time[1] = '0' + (clock_reg[0] & 0x0F);
}
else
{
time[0] = '0' + ((clock_reg[0] >> 4) & 0x03);
time[1] = '0' + (clock_reg[0] & 0x0F);
}
time[2] = ':';
time[3] = '0' + ((clock_reg[1] >> 4) & 0x0F);
time[4] = '0' + (clock_reg[1] & 0x0F);
time[5] = ':';
time[6] = '0' + ((clock_reg[2] >> 4) & 0x0F);
time[7] = '0' + (clock_reg[2] & 0x0F);
time[8] = '\0';
}
static void get_date(void)
{
calender_reg[0] = read_ds1307(YEAR_ADDR);
calender_reg[1] = read_ds1307(MONTH_ADDR);
calender_reg[2] = read_ds1307(DATE_ADDR);
calender_reg[3] = read_ds1307(DAY_ADDR);
date[0] = '2';
date[1] = '0';
date[2] = '0' + ((calender_reg[0] >> 4) & 0x0F);
date[3] = '0' + (calender_reg[0] & 0x0F);
date[4] = '-';
date[5] = '0' + ((calender_reg[1] >> 4) & 0x0F);
date[6] = '0' + (calender_reg[1] & 0x0F);
date[7] = '-';
date[8] = '0' + ((calender_reg[2] >> 4) & 0x0F);
date[9] = '0' + (calender_reg[2] & 0x0F);
date[10] = '\0';
}
void init_config(void)
{
init_clcd();
init_i2c();
init_ds1307();
clcd_print(" DS1307 TEST ", LINE1(0));
}
void main(void)
{
init_config();
while (1)
{
#if 1
get_time();
display_time();
#else
get_date();
display_date();
#endif
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
#endif
Brief:
Source Code:
can.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : can.c
* Title : CAN Driver
* Description : CAN Driver Module to communicate on a network using different modes
*-----------------------------------------------------------------------------------------------*/
#include "can.h"
#include "main.h"
#include "clcd.h"
/* Global Variables */
unsigned char can_payload[13];
typedef enum _CanOpMode
{
e_can_op_mode_bits = 0xE0, /* Use this to access opmode bits */
e_can_op_mode_normal = 0x00,
e_can_op_mode_sleep = 0x20,
e_can_op_mode_loop = 0x40,
e_can_op_mode_listen = 0x60,
e_can_op_mode_config = 0x80
} CanOpMode;
/* Configure the CAN Module */
void init_can(void)
{
/* CAN_TX = RB2, CAN_RX = RB3 */
TRISB2 = 0; /* CAN TX */
TRISB3 = 1; /* CAN RX */
/* Enter CAN module into config mode */
CANSTAT &= 0x1F; /* clear previous mode */
CANSTAT |= 0x80; /* set new mode */
/* Wait untill desired mode is set */
while (CANSTAT != 0x80);
/* Enter CAN module into Mode 0 */
ECANCON = 0x00;
/* Initialize CAN Timing 8MHz */
BRGCON1 = 0xE1; /* 1110 0001, SJW=4, TQ, BRP 4 */
BRGCON2 = 0x1B; /* 0001 1011, SEG2PHTS 1 sampled once PS1=4TQ PropagationT 4TQ */
BRGCON3 = 0x03; /* 0000 0011, PS2, 4TQ */
/*
* Enable Filters
* Filter 0
*/
RXFCON0 = 0x01;
/*
* Initialize Receive Filters
* Filter 0 = 0xFFC
*/
RXF0EIDH = 0x00;
RXF0EIDL = 0x00;
RXF0SIDH = 0x6B;
RXF0SIDL = 0xC0;
/* Enter CAN module into Loop back mode */
CAN_SET_OPERATION_MODE_NO_WAIT(e_can_op_mode_loop);
/* Set Receive Mode for buffers */
RXB0CON = 0x00;
}
/* Check the buffers, if it have message */
unsigned char can_receive(void)
{
if (RXB0FUL) /* CheckRXB0 */
{
can_payload[EIDH] = RXB0EIDH;
can_payload[EIDL] = RXB0EIDL;
can_payload[SIDH] = RXB0SIDH;
can_payload[SIDL] = RXB0SIDL;
can_payload[DLC] = RXB0DLC;
can_payload[D0] = RXB0D0;
can_payload[D1] = RXB0D1;
can_payload[D2] = RXB0D2;
can_payload[D3] = RXB0D3;
can_payload[D4] = RXB0D4;
can_payload[D5] = RXB0D5;
can_payload[D6] = RXB0D6;
can_payload[D7] = RXB0D7;
RXB0FUL = 0;
RXB0IF = 0;
return TRUE;
}
else
{
return FALSE;
}
}
/* Transmit Sample Mesaage */
void can_transmit(void)
{
TXB0EIDH = 0x00; /* Extended Identifier */
TXB0EIDL = 0x00; /* Extended Identifier */
/* 0x35E 0110 1011 110 */
TXB0SIDH = 0x6B; /* Standard Identifier */
TXB0SIDL = 0xC0; /* Standard Identifier */
TXB0DLC = 0x08; /* Data Length Count */
TXB0D0 = 'A'; /* DataByte 0 */
TXB0D1 = 'B'; /* DataByte 1 */
TXB0D2 = 'C'; /* DataByte 2 */
TXB0D3 = 'D'; /* DataByte 3 */
TXB0D4 = 'E'; /* DataByte 4 */
TXB0D5 = 'F'; /* DataByte 5 */
TXB0D6 = 'G'; /* DataByte 6 */
TXB0D7 = 'H'; /* DataByte 7 */
TXB0REQ = 1; /* Set the buffer to transmit */
}
can.h
#ifndef CAN_H
#define CAN_H
/* Defines ECAN */
#define F_ECAN_MODE2_FP CANCON & 0x0F
#define F_ECANFIFO_0 RXB0CONbits.RXFUL
#define F_ECANFIFO_1 RXB1CONbits.RXFUL
#define F_ECANFIFO_2 B0CONbits.RXFUL
#define F_ECANFIFO_3 B1CONbits.RXFUL
#define F_ECANFIFO_4 B2CONbits.RXFUL
#define F_ECANFIFO_5 B3CONbits.RXFUL
#define F_ECANFIFO_6 B4CONbits.RXFUL
#define F_ECANFIFO_7 B5CONbits.RXFUL
#define CAN_SET_OPERATION_MODE_NO_WAIT(mode) \
{ \
CANCON &= 0x1F; \
CANCON |= mode; \
}
#define EIDH 0
#define EIDL 1
#define SIDH 2
#define SIDL 3
#define DLC 4
#define D0 5
#define D1 6
#define D2 7
#define D3 8
#define D4 9
#define D5 10
#define D6 11
#define D7 12
/* Global Variable */
extern unsigned char can_payload[13];
/* Function Prototypes */
void init_can(void);
unsigned char can_receive(void);
void can_transmit(void);
#endif
clcd.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : clcd.c
* Title : CLCD Driver
* Description : Module to make CLCD work in 8 bit mode
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "clcd.h"
void clcd_write(unsigned char byte, unsigned char control_bit)
{
CLCD_RS = control_bit;
CLCD_PORT = byte;
/* Should be atleast 200ns */
CLCD_EN = HI;
CLCD_EN = LO;
PORT_DIR = INPUT;
CLCD_RW = HI;
CLCD_RS = INSTRUCTION_COMMAND;
do
{
CLCD_EN = HI;
CLCD_EN = LO;
} while (CLCD_BUSY);
CLCD_RW = LO;
PORT_DIR = OUTPUT;
}
void init_clcd()
{
/* Set PortD as output port for CLCD data */
TRISD = 0x00;
/* Set PortC as output port for CLCD control */
TRISC = TRISC & 0xF8;
CLCD_RW = LO;
TWO_LINE_5x7_MATRIX_8_BIT;
CURSOR_HOME;
DISP_ON_AND_CURSOR_OFF;
CLEAR_DISP_SCREEN;
}
void clcd_print(const unsigned char *data, unsigned char addr)
{
clcd_write(addr, INSTRUCTION_COMMAND);
while (*data != '\0')
{
clcd_write(*data++, DATA_COMMAND);
}
}
void clcd_putch(const unsigned char data, unsigned char addr)
{
clcd_write(addr, INSTRUCTION_COMMAND);
clcd_write(data, DATA_COMMAND);
}
clcd.h
#ifndef CLCD_H
#define CLCD_H
#define HI 1
#define LO 0
#define INPUT 0xFF
#define OUTPUT 0x00
#define DATA_COMMAND 1
#define INSTRUCTION_COMMAND 0
#define LINE1(x) (0x80 + (x))
#define LINE2(x) (0xC0 + (x))
#define TWO_LINE_5x7_MATRIX_8_BIT clcd_write(0x38, INSTRUCTION_COMMAND)
#define CLEAR_DISP_SCREEN clcd_write(0x01, INSTRUCTION_COMMAND)
#define CURSOR_HOME clcd_write(0x02, INSTRUCTION_COMMAND)
#define DISP_ON_AND_CURSOR_OFF clcd_write(0x0C, INSTRUCTION_COMMAND)
#define CLCD_PORT PORTD
#define CLCD_EN RC2
#define CLCD_RS RC1
#define CLCD_RW RC0
#define CLCD_BUSY RD7
#define PORT_DIR TRISD7
void init_clcd(void);
void clcd_print(const unsigned char *data, unsigned char addr);
void clcd_putch(const unsigned char data, unsigned char addr);
void clcd_write(unsigned char bit_values, unsigned char control_bit);
#endif
main.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : main.c
* Title : Controller Area Network
* Description : A simple appication demonstrating CAN communication using loop back
* method
*-----------------------------------------------------------------------------------------------*/
#include "main.h"
#include "matrix_keypad.h"
#include "can.h"
#include "clcd.h"
/* delay 1ms function */
void delay(unsigned short factor)
{
unsigned short i, j;
for (i = 0; i < factor; i++)
{
for (j = 500; j--; );
}
}
void init_config(void)
{
/* Initialize Matrix Keypad */
init_matrix_keypad();
/* Initialize CLCD module */
init_clcd();
/* Initialize CAN module */
init_can();
/* Set buzzer as output */
TRISE0 = 0;
BUZZER = 0;
clcd_print("CAN Bus Demo", LINE1(2));
}
void can_demo(void)
{
unsigned char key;
unsigned char i = 0;
key = read_switches(1);
if (key == MK_SW1)
{
clcd_print("Tx DATA : --> ", LINE2(0));
can_transmit();
delay(1000);
}
if (can_receive())
{
clcd_print("Rx DATA : <--", LINE2(0));
i = 0;
while (i != 8)
{
clcd_putch(can_payload[D0 + i], LINE2(14));
i++;
/* ON Sound */
//BUZZER = 1;
delay(500);
BUZZER = 0;
}
}
}
void main(void)
{
init_config();
while (1)
{
can_demo();
}
}
main.h
#ifndef MAIN_H
#define MAIN_H
#include <xc.h>
#define _XTAL_FREQ 20000000
#pragma config OSC = XT
#pragma config WDT = OFF
#pragma config BOREN = OFF
#pragma config PBADEN = OFF
#pragma config LVP = OFF
/* Defines the data */
#define TRUE 1
#define FALSE 0
#define BUZZER RE0
#define LED_PORT PORTB
#define LED7 RB6
#define LED8 RB7
#endif
matrix_keypad.c
/*-------------------------------------------------------------------------------------------------
* Author : Emertxe (https://emertxe.com)
* Date : Wed 24 Mar 2021 16:00:04 IST
* File : matrix_keypad.c
* Title : Matrix Keypad - Driver
* Description : A module which detects both level and state change of user input using
* matrix keypad
*-----------------------------------------------------------------------------------------------*/
#include "matrix_keypad.h"
#include "main.h"
void init_matrix_keypad(void)
{
/* Config PORTB as digital */
ADCON1 = 0x0F;
/* Set Rows (RB7 - RB5) as Outputs and Columns (RB4 - RB1) as Inputs */
TRISB = 0x1E;
/* Set PORTB input as pull up for columns */
RBPU = 0;
MATRIX_KEYPAD_PORT = MATRIX_KEYPAD_PORT | 0xE0;
}
unsigned char scan_key(void)
{
ROW1 = LO;
ROW2 = HI;
ROW3 = HI;
if (COL1 == LO)
{
return 1;
}
else if (COL2 == LO)
{
return 4;
}
else if (COL3 == LO)
{
return 7;
}
else if (COL4 == LO)
{
return 10;
}
ROW1 = HI;
ROW2 = LO;
ROW3 = HI;
if (COL1 == LO)
{
return 2;
}
else if (COL2 == LO)
{
return 5;
}
else if (COL3 == LO)
{
return 8;
}
else if (COL4 == LO)
{
return 11;
}
ROW1 = HI;
ROW2 = HI;
ROW3 = LO;
/* TODO: Why more than 2 times? */
ROW3 = LO;
if (COL1 == LO)
{
return 3;
}
else if (COL2 == LO)
{
return 6;
}
else if (COL3 == LO)
{
return 9;
}
else if (COL4 == LO)
{
return 12;
}
return 0xFF;
}
unsigned char read_switches(unsigned char detection_type)
{
static unsigned char once = 1;
unsigned char key;
key = scan_key();
if (detection_type == STATE_CHANGE)
{
if ((key != ALL_RELEASED) && once)
{
once = 0;
return key;
}
else if (key == ALL_RELEASED)
{
once = 1;
}
}
else if (detection_type == LEVEL_CHANGE)
{
return key;
}
return 0xFF;
}
matrix_keypad.h
#ifndef MATRIX_KEYPAD_H
#define MATRIX_KEYPAD_H
#define MAX_ROW 4
#define MAX_COL 3
#define STATE_CHANGE 1
#define LEVEL_CHANGE 0
#define MK_SW1 1
#define MK_SW2 2
#define MK_SW3 3
#define MK_SW4 4
#define MK_SW5 5
#define MK_SW6 6
#define MK_SW7 7
#define MK_SW8 8
#define MK_SW9 9
#define MK_SW10 10
#define MK_SW11 11
#define MK_SW12 12
#define ALL_RELEASED 0xFF
#define HI 1
#define LO 0
#define MATRIX_KEYPAD_PORT PORTB
#define ROW3 RB7
#define ROW2 RB6
#define ROW1 RB5
#define COL4 RB4
#define COL3 RB3
#define COL2 RB2
#define COL1 RB1
void init_matrix_keypad(void);
unsigned char scan_key(void);
unsigned char read_switches(unsigned char detection_type);
#endif