0% found this document useful (0 votes)
2 views18 pages

Report1 - Final

This document outlines a micro-controller course exercise involving the PIC16F877A microcontroller. It details the setup for input and output components, programming functions for LCD display, and the main program structure for executing three exercises. Each exercise focuses on different functionalities such as frequency measurement, pulse counting, and analog signal processing using ADC.

Uploaded by

Khoa Nguyễn
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views18 pages

Report1 - Final

This document outlines a micro-controller course exercise involving the PIC16F877A microcontroller. It details the setup for input and output components, programming functions for LCD display, and the main program structure for executing three exercises. Each exercise focuses on different functionalities such as frequency measurement, pulse counting, and analog signal processing using ADC.

Uploaded by

Khoa Nguyễn
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 18

HO CHI MINH NATIONAL UNIVERSITY

HO CHI MINH UNIVERSITY OF TECHNOLOGY

🙞···☼···🙜

MICRO-CONTROLLER COURSE
CLASS EXERCISE 2

Lecturer: Assoc. Prof: Lê Đức Hạnh

STUDENT NAME STUDENT ID


Nguyễn Ngọc Khoa 2053139
Phạm Anh Hoàng 2152082
Vũ Minh Dũng 2152489
Lê Thành 2052706
Ngô Duy Hưng 2053072

HO CHI MINH CITY, 2024


Components

I. Output
This is the output of the project, every result will be printed on the LCD display

Since we’re operating in 4-bit mode, we connect the LCD as follows:


- VSS, VDD are power pins therefore they are connected to the power source.
- VEE controls the screen brightness so it will be set to HIGH for maximum brightness
in this case.
- D0 ~ D1, RW pins are connected to ground as they are not required for 4-bit
operations.
- RS, E, D4 ~ D7 pins are connected to pins RB2 to RB3 on the microcontroller
respectively.

II. Input
1. Control buttons
Three buttons are used for switching between the exercises 1, 2 and 3. They are
connected to pin RD0, RD1 and RD2 respectively.

And the resistors R1, R2 and R3 act as pull-down resistors so that the inputs will
initially be on a LOW state.

2. Square wave

The input required for exercise 1, it is set-up with the settings below:
3. Count button
This in the input for exercise 2, used to manually send pulses to the micro controller.

4. Potentiometer
Three potentiometers are connected to pin RA0, RA1 and RA2 on the microcontroller
for exercise 3 with the reference voltage (5V) connected to pin RA3.

5. Crystal oscillator
An external oscillator is connected to the microcontroller to generate the frequency in
which the microcontroller operates.
The oscillator configurations:

III. Processing
1. PIC16F877A
In this exercise, we’ll be using the PIC16F877A microcontroller as requested.
We only need to connect the VPP pin to the power source.
Programming
I. Initial setup
1. Global Variables
These are just variables declared beforehand, their purposes will be explained later.
#define EN PORTB.B3
#define RS PORTB.B2

unsigned int lcd_state = 0;


int num[15];
long ad_time = 6;

2. LCD related functions


a) lcd_cmd
Sends a command to the LCD by writing the upper 4 bits first, then the lower 4
bits.
void lcd_cmd(unsigned char cmd)
{
PORTB = (cmd&0xF0); //Write the upper 4-bits of the data
EN = 1;
RS = 0;
EN = 0;
PORTB = ((cmd<<4)&0xF0); //Write the lower 4-bits of the data
EN = 1;
RS = 0;
EN = 0;
delay_ms(3); //Small delay for the LCD to process the data
}

b) lcd_send
Similar to lcd_cmd but instead, setting the RS pin to HIGH, indicates that this is a
character to print.
void lcd_send(unsigned char send)
{
PORTB = (send&0xF0); //Write the upper 4-bits of the data
EN = 1;
RS = 1;
EN = 0;
PORTB = ((send<<4)&0xF0); //Write the lower 4-bits of the data
EN = 1;
RS = 1;
EN = 0;
delay_ms(3); //Small delay for the LCD to process the data
}
c) lcd_string
Use a loop to send multiple character to the LCD
void lcd_string(const unsigned char *str, unsigned char num)
{
unsigned int i;
for( i = 0; i < num; i++)
{
lcd_send(str[i]); //Send each character to the LCD seperately
}
}

d) lcd_init
Send a series of commands to the LCD in order to turn on the LCD as well as
configuring it’s operating mode.
void lcd_init()
{
delay_ms(50); //LCD Power ON delay

lcd_cmd(0x30); /////////////////////////
delay_ms(40); // //
lcd_cmd(0x30); // //
delay_ms(10); // Reset the LCD //
lcd_cmd(0x30); // //
delay_ms(10); /////////////////////////
lcd_cmd(0x02); //Function set

lcd_cmd(0x28); //4-bit mode, 2 lines, 5x7 matrix


lcd_cmd(0x0E); //Display ON, Cursor OFF
lcd_cmd(0x06); //Entry mode
lcd_cmd(0x01); //Clear display
}

e) lcd_num
Print out an integer to the LCD digits by digits.
void lcd_num(float n)
{
long tmpf = n;
int p;
int k=0;
while(tmpf>0)
{
num[k]=tmpf%10;
tmpf=tmpf/10;
k++;
}
k--;
for (p=k;p>=0;p--)
{
lcd_send(num[p]+48);
}
}
f) lcd_float
Print out a decimal number with a precision up of 0.1
void lcd_float(float n)
{
long tmpf = n*10;
int p;
int k=0;
while(tmpf>0)
{
num[k]=tmpf%10;
tmpf=tmpf/10;
k++;
}
k--;
for (p=k;p>=1;p--)
{
lcd_send(num[p]+48);
}
if(n<1) lcd_send('0');
lcd_send('.');
lcd_send(num[0]+48);
lcd_send(' ');

}
II. Main program
1. Algorithm
a) Initial setup
A series of commands to set the working mode for each pin.
After that, initialize the LCD and setup the Timer 1.
The timer 1 will only be used for timing purposes in this program
void main(void)
{
PORTA = 0x00; //Clear all A pins
PORTB = 0x00; //Clear all B pins
PORTD = 0x00; //Clear all D pins

TRISA = 0xFF; //Set pin A0~A5 as input


TRISB = 0x01; //Set pin B1~B7 as output
TRISD = 0xFF; //Set pin D0~D7 as input

lcd_init(); //Initialize the LCD

T1CON.TMR1CS = 0; //Select normal mode for timer 1


T1CON.T1CKPS0 = T1CON.T1CKPS1 = 0; //Prescaler 1:1

b) Main loop
Here we have the main operation for the PIC
As stated before, we have three buttons to switch between the exercises,
Each button will set the variable [ lcd_state] to 1 for exercise 1, 2 for exercise 2
and 3 for exercise 3.

The [lcd_state] variable will also determine if we needed to clear the display
before each exercise. Without it, the PIC will tell the LCD to clear each loop,
resulting in a flickering screen and bigger delay between each loop due to
unnecessary commands.

while(1)
{

//-----------------------------Setup-for-question-1----------------------------

if (PORTD.B0 == 1) //if button 1 pressed change to question 1


{
if(lcd_state != 1) //clear display if needed
{
lcd_cmd(0x01);
lcd_state = 1;
} else lcd_state = 1;

lcd_cmd(0x80);
lcd_string("Freq:",5);
lcd_cmd(0xC0);
lcd_string("High: ", 6);
}

//-----------------------------Setup-for-question-2----------------------------

if (PORTD.B1 == 1) //if button 2 pressed change to question 2


{
if(lcd_state != 2) //clear display if needed
{
lcd_cmd(0x01);
lcd_state = 2;
} else lcd_state = 2;

lcd_cmd(0x80);
lcd_string("Pulses read:",12);
lcd_cmd(0xC0);
lcd_send('0');

OPTION_REG.T0CS = 1; //Select counter mode for timer 0


OPTION_REG.T0SE = 1; //Negative transition
OPTION_REG.PSA = 0; //Don’t select custom prescaler
PORTA.B4 == 0;
}

//----------------------------Setup-for-question-3-----------------------------

if (PORTD.B2 == 3) //if button 3 pressed change to question 3


{
if(lcd_state != 3) //clear display if needed
{
lcd_cmd(0x01);
lcd_state = 3;
} else lcd_state = 3;

lcd_cmd(0x80);
lcd_string("AN0 - AN1 - AN2",15);

ADCON1 = 0x83;
}

//-----------------------------------------------------------------------------

switch(lcd_state)
{
case 1:
{
get_frequency(); //question 1
} break;

case 2:
{
if(PORTA.B4 == 1) pulse_count(); //question 2
} break;

case 3:
{
if(ad_time < 7) ad_value(); //question 3
else ad_time = 1;
} break;
}
}
return;
}

2. Exercise 1
a) Theory
In order to get the frequency from the input pulse, we can count the number of
ticks from the timer and then use the following formula:
CPU frequency
f=
4 × Prescaler × N umber of ticks
We have:
- CPU frequency=4 000000 ( Hz)
- Prescaler=8
- Number of ticks : will be measured

Next up is the pulse width. We can use similar method of counting ticks to get our
results:
HIGH period
Pulse width= × 100 %
Pulse period
b) Coding
First we declare some variables for the function:
- [float h]: HIGH period recorded in timer ticks
- [float l]: The pulse period recorded in timer ticks
- [float f]: Frequency of the pulse
Then we set-up the timer 0 as follows:
void get_frequency()
{
float h, l, f;
OPTION_REG.T0CS = 0; //Select normal mode
OPTION_REG.PSA = 0; //Select custom prescaler
OPTION_REG.PS2 = 0; //
OPTION_REG.PS1 = 1; //Timer0 Prescaler 1:8
OPTION_REG.PS0 = 0; //
After that we can begin by waiting out the current period then set the timer value
[TMR0] to 0 and start counting.
We stop counting when the pulse switch to HIGH the second time and assign
[TMR0] value to the required variables.
while(PORTC.B0 == 1) {}
while(PORTC.B0 == 0) {}
TMR0 = 0;
while(PORTC.B0 == 1) {}
while(PORTC.B0 == 0) {}
l = TMR0;
f = 1000000/l/8;
lcd_cmd(0x86); lcd_float(f); lcd_string("Hz",2);
while(PORTC.B0 == 1) {}
while(PORTC.B0 == 0) {}
TMR0 = 0;
while(PORTC.B0 == 1) {}
h = TMR0;
while(PORTC.B0 == 0) {}
l = TMR0;
lcd_cmd(0xC6); lcd_float(h/l*100); lcd_send('%');
}
After getting all the needed values and calculations, we printout the result.
c) Simulation
https://drive.google.com/file/d/1RkQ1YLou09Fm8WeV2n74USksYtzPGLLR/
view?usp=drive_link

3. Exercise 2
a) Theory
Use Timer 1 as a delay timer but instead of waiting for the [TMR1IF_bit] and do
nothing, we include a print function in the loop.
b) Coding
Since we already set-up Timer 1 in normal mode in the “Initial setup” section and
Timer 0 in counter mode, we don’t need to do that here.
void pulse_count()
{
long count = 0;
long time = 0;
int i, state;

TMR0 = 0;

for(i=0; i< 60; i++) //50ms repeated 60 times


{
TMR1H = 15536 >> 8;
TMR1L = 15536 & 0x00FF;
T1CON.TMR1ON = 1;
while(!TMR1IF_bit)
{
lcd_cmd(0xC0);
lcd_num(TMR0);
}
TMR1IF_bit = 0;
T1CON.TMR1ON = 0;
}
lcd_cmd(0xC0);
lcd_send('0');
lcd_send(' ');
lcd_send(' ');
}
a) Simulation
https://drive.google.com/file/d/1A8VkSSkIpW5kbjBHFc5Yv4wPr86fI4IA/view?
usp=sharing

4. Exercise 3
a) Theory
This time we will use the [ad_time] variable we mentioned above.
Each 1 second loop, we will increase [ad_time] by 1
- Every loop, we will read and convert signal from AN0
- Every two loop, when [ad_time] is divisible by 2,we will read and convert
signal from AN1
- Every three loop,when [ad_time] is divisible by 3, we will read and convert
signal from AN1
The algorithm is shown in the block diagram below:
b) Coding:
void ad_value()
{
unsigned int i, adc_value = 0, tmp[4];

TMR1H = 15536 >> 8;


TMR1L = 15536 & 0x00FF;
T1CON.TMR1ON = 1;

ADCON0 = 0x80;

if(ad_time > 0)
{
CHS2_bit = 0; CHS1_bit = 0; CHS0_bit = 0; //Select channel AN0
ADON_bit = 1; //Turn on the ADC

delay_ms(5); //Small delay


GO_DONE_bit = 1; //Start the ADC conversion
delay_ms(5);
while(ADIF_bit == 0) {} //Wait for the conversion to complete

adc_value = ADRESH<<8; //
adc_value += ADRESL; //assgin the result to adc_value
ADON_bit = 0;

lcd_cmd(0xC0);
lcd_string(" ",4);

lcd_cmd(0xC0);
lcd_num(adc_value); //print out the result
}

if(ad_time %2==0)
{
CHS2_bit = 0; CHS1_bit = 0; CHS0_bit = 1; //Select channel AN1
ADON_bit = 1; //Turn on the ADC

delay_ms(5); //Small delay


GO_DONE_bit = 1; //Start the ADC conversion
delay_ms(5);
while(ADIF_bit == 0) {} //Wait for the conversion to complete

adc_value = ADRESH<<8; //
adc_value += ADRESL; //assgin the result to adc_value
ADON_bit = 0;

lcd_cmd(0xC6);
lcd_string(" ",4);

lcd_cmd(0xC6);
lcd_num(adc_value); //print out the result

}
delay_ms(10);
if(ad_time %3==0)
{
CHS2_bit = 0; CHS1_bit = 1; CHS0_bit = 0; //Select channel AN2
ADON_bit = 1; //Turn on the ADC

delay_ms(5); //Small delay


GO_DONE_bit = 1; //Start the ADC conversion
delay_ms(5);
while(ADIF_bit == 0) {} //Wait for the conversion to complete

adc_value = ADRESH<<8; //
adc_value += ADRESL; //assgin the result to adc_value
ADON_bit = 0;

lcd_cmd(0xCC);
lcd_string(" ",4);

lcd_cmd(0xCC);
lcd_num(adc_value); //print out the result
}
ad_time++;
while(!TMR1IF_bit){}
TMR1IF_bit = 0;

for(i = 1; i<20; i++) //Wait out 1 second


{
TMR1H = 15536 >> 8;
TMR1L = 15536 & 0x00FF; //50ms period
T1CON.TMR1ON = 1;
while(!TMR1IF_bit){}
TMR1IF_bit = 0;
}
}

a) Simulation
https://drive.google.com/file/d/1j5EiPRAGLt8wXEuZXIXJ_LOAANrS5Drr/
view?usp=sharing

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy