NX-887 Experiment documentation 1
PIC16F887 microcontroller Experiment Experiment 1 Input/Output port Experiment 1.1 : Drive LED with PORTC This experiment demonstrates using PORTC of PIC16F887 as output to drives the blinking LED. The experimental C code that developed by HI-TECH C compiler and MPLAB IDE is shown in Listing L1-1.
Experimental circuit : +5V
11 Vcc
32 Vcc
+5V R1 10k
R2 510
LED8-LED1
PIC16F887 1
RC7 26
MCLR
SW1 RESET
RC6 25 RC5
24
RC4 23 RC3 12 31
RC2 17
GND
RC1 16
GND
RC0
OSC1
15
OSC2
13 C1 22pF
18
14 XTAL1 20MHz
C2 22pF
RN1 390*8
2 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void Delay_ms(unsigned int tick) { while(tick—) // Loop couter delay time { __delay_ms(1); // Delay 1 ms } } void main() { TRISC = 0x00; // Set PORTC output mode while(1) { PORTC = 0x00; // LED at PORTC ON Delay_ms(500); // Delay 0.5 sec PORTC = 0xFF; // LED at PORTC OFF Delay_ms(500); // Delay 0.5 sec } }
Listing L1-1 : output_01.c file for setting PORTC of PIC16F887 to output for driving LEDs
NX-887 Experiment documentation 3
Experiment 1.2 : Drive LED at PORTC with invert logic technique This experment demonstrates using PORTC as output to drive LEDs with invert logic technique programming by using ~ or NOT operator. You still use figure L1-1 in this experiment. The experimental C code is shown in Listing L1-2.
Experimental circuit : Same with the experiment 1.1
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void Delay_ms(unsigned int tick) { while(tick—) // Loop couter delay time { __delay_ms(1); // Delay 1 ms } } void main() { TRISC = 0x00; // Set PORTC output mode while(1) // Infinite loop { PORTC = ~PORTC; // LED at PORTC tooggle Delay_ms(500); // Delay 0.5 sec } }
Listing L1-2 : output_02.c file for setting PORTC of PIC16F887 to output for driving LEDs with invert logic technique
4 NX-887
Experiment documentation
Experiment 1.3 : Port control in bit manipulation This experiment demonstrates how to control microcontroller port in bit. We write data one bit to RC3 port of PIC16F887 to drive LED. The experimental C code is shown in Listing L1-3.
Experimental circuit : +5V
32 11 Vcc Vcc R9 10k
PIC16F887 1
RC3
MCLR
18 R1 390
SW1 RESET 12 31
GND GND OSC1
OSC2
13 C1 22pF
14 XTAL1 20MHz
C2 22pF
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void Delay_ms(unsigned int tick) { while(tick—) // Loop couter delay time { __delay_ms(1); // Delay 1 ms } } void main() { TRISC3 = 0; // Set RC output mode while(1) // Infinite loop { RC3 = 1; // LED at RC3 ON Delay_ms(500); // Delay 0.5 sec RC3 = 0; // LED at RC3 OFF Delay_ms(500); // Delay 0.5 sec } }
Listing L1-3 : output_03.c file for one bit port control of PIC16F887
NX-887 Experiment documentation 5
Experiment 1.4 : PORTB as output This experimnet demonstrates how to set the PORTB of PIC16F887 as output. The experimental C code is shown in Listing L1-4.
Experimental circuit : +5V
11 Vcc
32 Vcc
+5V R1 10k
R2 510
LED1-LED8
PIC16F887 1
RB7 40
MCLR
SW1 RESET
RN1 390*8
RB6 39 RB5
38
RB4 37 RB3
36
RB2 35 RB1 34 12 31
GND
RB0
33
GND OSC1 13
C1 22pF
OSC2 14 XTAL1 20MHz
C2 22pF
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void Delay_ms(unsigned int tick) { while(tick—) // Loop counter delay time { __delay_ms(1); // Delay 1 ms } } void main() { TRISB = 0; // Set PORTB output mode while(1) { PORTB = 0xFF; // LED at PORTB ON Delay_ms(500); // Delay 0.5 sec PORTB = 0x00; // LED at PORTB OFF Delay_ms(500); // Delay 0.5 sec } }
Listing L1-4 : output_04.c file for setting PORTB of PIC16F887 as outpiut port
6 NX-887
Experiment documentation
Experiment 1.5 : Switch-controlled PORTC This experiment demonstrates how to use PORTA, B and E of PIC16F887 as input port to control PORTC status. The experimental C code is shown in Listing L1-5.
Experimental circuit : +5V
R5 10k
R1 10k
C3 0.1F
11 32 Vcc R2 510
PIC16F887 1
MCLR
RC7 26
SW1 RESET
R3 10k
R4 10k
LED8-LED1
RC6 25 8
RC5 RE0
RC3 33
24
RC4 23
S3 RE0
18
RC2 17
RB0
RC1 16
S2 RB0
RC0 6
15
GND
RA4
GND
S1 RA4
RN1 390*8
OSC1 13 C1 22pF
12 31
OSC2 14 XTAL1 20MHz
C2 22pF
The operatiuon begins with all LEDs at Port C off. 1. If swtich at RB0 pin is pressed, LED at Port C display binary value from 00000000 to 11111111. 2. If swtich at RA4 pin is pressed, LED at Port C display binary value decrease from 11111111 .to 00000000. 3. If swtich at RE0 pin is pressed, LED at Port C are off.
NX-887 Experiment documentation 7
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void Delay_ms(unsigned int tick) { while(tick—) // Loop counter delay time { __delay_ms(1); // Delay 1 ms } } void main() { TRISC = 0; PORTC = 0; ANS6 = 0; ANS12 = 0; TRISB0 = 1; TRISA4 = 1; TRISE1 = 1; while(1) { if(RB0==0) { PORTC++; Delay_ms(200); } if(RA4==0) { PORTC—; Delay_ms(200); } if(RE1==0) { PORTC = 0; Delay_ms(200); } } }
// // // // // // // //
Set PORTC output mode Clear port Set RE1 as digital port Set RB0 as digital port Set RB0 input mode Set RA4 input mode Set RE1 input mode Infinite loop
// Switch at RB0 press? // Increase data of PORTC 1 time // Delay 0.5 sec // Switch at RA4 press? // Decrease data of PORTC 1 time // Delay 0.5 sec // Switch at RE1 press? // Clear data of PORTC // Delay 0.5 sec
Listing L1-5 : input_01.c file for using PORTA, B and E as input to control PORTC output port operation.
8 NX-887
Experiment documentation
PIC16F887 microcontroller Experiment Experiment 2 : Simple sound generator This experiment demonstrates how to using PIC16F887 to generate the simple soung signal and drives to a piezo speaker. The experimental C code is shown in Listing L2-1.
Experimental circuit : +5V
R1 10k
C3 0.1F
11 32 Vcc R2 510 1
PIC16F887 MCLR
SW1 RESET
R3 10k
C3 10/16V
R4 10k
RC0 33
GND 6
+
RB0
S2 RB0
S1 RA4
15
GND RA4 OSC1 13 C1 22pF
OSC2 14 XTAL1 20MHz
C2 22pF
12 31
SPK1 Piezo Speaker
NX-887 Experiment documentation 9
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void Delay_ms(unsigned int tick) { while(tick—) // Loop counter delay time { __delay_ms(1); // Delay 1 ms } } void Delay_sound(unsigned int tick) // Delay 100 us per tick { while(tick—) { __delay_us(90); // Delay 90 us } } void Sound(unsigned int freq,unsigned int time) { unsigned int dt=0,m=0; // Keep value and TRISC0 = 0; // Set RC0 output mode dt = 5000/freq; // Keep active logic delay time = (5*time)/dt; // Keep counter for generate sound for(m=0;m<time;m++) // Sound generate loop (Toggle logic RC0) { RC0 = 1; // RC0=1 Delay_sound(dt); // Delay for sound RC0 = 0; // RC0=0 Delay_sound(dt); // Delay for sound } } void Beep() { Sound(800,100); // Generate sound 800Hz,0.1 second } void main() { ANS12 = 0; // Set RB0 as digital port TRISB0 = 1; // Set RB0 input mode TRISA4 = 1; // Set RA4 input mode while(1) // Infinite loop { if(RB0==0) // Switch at RB0 press? { Sound(2000,500); // Sound 2000Hz,0.5 second Delay_ms(200); // Delay 0.5 second } if(RA4==0) // Switch at RA4 press? { Beep(); // Sound beep 1 time Delay_ms(200); // Delay 0.5 second } } } Important function description Delay_sound : delay 100 microsecond per unit. This function works with standard function of compiler.
__delay_us
Sound : generates sound signal at RC0 port with setting frequency and duration. Beep : generates 800Hz signal at RC0 in 0.1 second.
Listing 2-1 : sound_01.c file for using PIC16F887 generates the simple sound signal for driving the piezo speaker
10 NX-887
Experiment documentation
PIC16F887 microcontroller Experiment Experiment 3 : LCD module interfacing Experiment 3.1 : Simple text message displaying This experiment demonstrates about creating the C code to control PIC16F887 with LCD module interfacing by using the custom LCD library; lcd887.h with lcd_puts function.
Experimental circuit : +5V
11
C3 0.1F
IC1 PIC16F887
+5V R1 10k
32
R2 510
+5V
RD2 21
4
22
6
RD3 1
SW1 RESET
30
RD7
29
RD6
28
RD5
27
RD4
12 31
C1 22pF
E
DSP1 LCD 16x2
+V Vo
MCLR
13
RS
XTAL1 20MHz
14 C2 22pF
D7 D6 D5 D4 D3 D2 D1 D0 R/W 14 13 12 11 10 9 8 7 5
GND 1
2 3 VR1 10k BRIGHTNESS
NX-887 Experiment documentation 11
//——————————————————————————————————————————// // LCD module library for HI-TECH C compiler // PIC16F887 : LCD16*2 // RD7 ==> D7 // RD6 ==> D6 // RD5 ==> D5 // RD4 ==> D4 // RD3 ==> E // RD2 ==> RS //——————————————————————————————————————————// #ifndef _LCD_H_ #define _LCD_H_ #include <pic.h> #include <stdlib.h> #define lcd_clear() lcd_command(1) #define lcd_origin() lcd_command(2) #ifndef _XTAL_FREQ #define _XTAL_FREQ 20000000 // Define Frequency 20.0 MHz for function __delay_ms #endif void delay(unsigned int tick) { while(tick—) // Loop counter delay time { __delay_ms(1); // Delay 1 ms } } void lcd_clk(void) /* Pulse LCD clock on EN*/ { RD3 = 1; delay(1); RD3 = 0; delay(1); } void lcd_command(unsigned char outbyte) /* Send command (4bit operation) */ { RD2=0; PORTD=(PORTD&0x0f)|(outbyte&0xf0); lcd_clk(); PORTD=(PORTD&0x0f)|((outbyte<<4)&0xf0); lcd_clk(); } void lcd_putc(unsigned char outbyte) /* Send Data (4bit operation) */ { RD2=1; PORTD=(PORTD&0x0f)|(outbyte&0xf0); lcd_clk(); PORTD=(PORTD&0x0f)|((outbyte<<4)&0xf0); lcd_clk(); } void lcd_puts(unsigned char line,char *p) { lcd_origin(); // Set origin address of LCD lcd_command(line); // Set address 00H of LCD while(*p) // Check data pointer = 0? { lcd_putc(*p); // Send data to LCD p++; // Increase one address } }
Listing L3-1 : lcd887.h library file for LCD interfacing experiment. This library is created from HI-TECH C compiler (continue)
12 NX-887
Experiment documentation
void inttolcd(unsigned char posi, long value) { char buff[16]; // Keep string for sending to LCD itoa(buff,value,10); lcd_puts(posi,buff); // Send integer to LCD } void lcd_init() { TRISD &= 0x03; PORTD = 0x00; RD3=0; RD2=0; delay(500); PORTD=(PORTD&0x0f)|0x30; // Force LCD to receive command per pulse at once lcd_clk(); PORTD=(PORTD&0x0f)|0x30; // (Do 3 times for ensuring LCD operation forced) lcd_clk(); PORTD=(PORTD&0x0f)|0x30; lcd_clk(); PORTD=(PORTD&0x0f)|0x20; // Switch to real 4 bit transfer mode on first lcd_clk(); lcd_command(0x28); // Send real command to set 4 bit operation lcd_command(0x01); // Clear all lcd_command(0x06); // Increase cursor automatic after byte lcd_command(0x0C); // Display on, no cursor, not blink lcd_command(0x02); // Home position lcd_command(0x01); // Clear all again } #endif
Listing L3-1 : lcd887.h library file for LCD interfacing experiment. This library is created from HI-TECH C compiler (final)
lcd877.h ; custom library for LCD module interfacing Hardware configuration PIC16F887’s pin
LCD module’s pin
RD7
D7
RD6
D6
RD5
D5
RD4
D4
RD3
E
RD2
RS
Additionally, R/W pin of LCD must connect with GND to select write-only mode. Listing L3-1 shows the sourcecode of lcd887.h library that using in this experiment and another experiments.
NX-887 Experiment documentation ď Źď&#x20AC; 13
Function description 1. lcd_init Initial LCD module to start the interfacing. Syntax
void lcd_init()
2. lcd_command Send command to LCD module Syntax
void lcd_command(unsigned char outbyte) Parameter outbyte : instruction code of LCD module
3. lcd_putc Display one character on LCD module screen Syntax
void lcd_putc(unsigned char outbyte) Parameter outbyte : displayed charactor data
4. lcd_puts Display string on LCD module screen Syntax
void lcd_puts(unsigned char line,char *p) Parameter line : set the LCD display address - The value range 0x80 to 0x8F are choosing the first line address from digit 1 to 16 respectively. - The value range 0xC0 to 0xCF are choosing the bottom line address from digit 1 to 16 respectively. p : select the displayed string
14 NX-887
Experiment documentation
5. inttolcd Convert the integer number (int) to display on LCD module screen Syntax
void inttolcd(unsigned char line, int
value)
Parameter line : set the LCD display address - The value range 0x80 to 0x8F are choosing the first line address from digit 1 to 16 respectively. - The value range 0xC0 to 0xCF are choosing the bottom line address from digit 1 to 16 respectively. value : the integer number
6. delay It is dealy time function in millisecond unit. Syntax
void delay(unsigned int tick) Parameter tick : delay time in millisecond The experimental C code is shown in Listing L3-2. #include <pic.h> // Include header file for MCU #include <lcd887.h> // Include Library for LCD display __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void main() { lcd_init(); // Initial LCD lcd_puts(0x80,”Hello world!”); while(1);
// Display message // Break program
}
Listing L3-2 : lcd_01.c; the experimental C code for PIC16F887 with LCD interfacing.
NX-887 Experiment documentation 15
Experiment 3.2 : Counter on LCD This experiment demonstrates a simple application of LCD interfacing. PIC16F887 counts data and shows the counter value on LCD module screen. The raw value will be set to int data type and convert to string for displaying on LCD screen with inttolcd function. The experimental C code is shown in Listing L3-3.
Experimental circuit : Same with the experiment 3.1
#include <pic.h> // Include header file for MCU #include <lcd887.h> // Include Library for LCD display __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP int i=0; // Keep counter void main() { lcd_init(); // Initial LCD lcd_puts(0x80,”Counter=”); // Show message at line 1 while(1) { inttolcd(0x89,i); // Show counter value delay(1000); // Delay 1.0 sec. i++; // Increase counter 1 time } }
Listing L3-3 : lcd_02.c; the experimental C code for PIC16F887 with LCD interfacing to display the counter value.
16 NX-887
Experiment documentation
PIC16F887 microcontroller Experiment Experiment 4 : External interrupt This experiment demonstrates PIC16F887’s external interrupt at RB0/INT pin. We assign the falling edge detection at RB0/INTpin. At that pin, connect a button swithc with a pullup resistor. After switch is pressed, the external interrupt is occured. PIC16F887 must response with interrupt service routine.
Interrupr service function of HI-TECH C compiler HI-TECH C compiler define interrupt service routine function as follows :
void interrupt name(void) { // Interrupt service routine } name is the name of the interrupt service function that can be customized independently. But should be avoided the reserved word in compiler. A function that is widely used INT_SERVICE. Within the interrupr service routine, developer may define a command to verify the interrupt flag bits to check back interrupt source. In the case of external interrupt at RB0/INT pin may be able to detect by using a sample function of the C programming language as follows : void interrupt INT_SERVICE(void) { if(INTF==1) // External interruprt flag is set ? { // External interrupt service routine INTF = 0; // Clear the exterrnal interrupt flag bit } } The experimental C code is shown in Listing L4-1.
NX-887 Experiment documentation 17
Experimental circuit : +5V
+5V
R1 10k
C3 0.1F
11 32 Vcc R2 510 1
LED8-LED1
PIC16F887
RC7 26
MCLR
RN1 390*8
RC6 25
SW1 RESET
RC5
R3 10k
24
RC4 23 RC3 33
18
RC2 17
RB0
RC1 16
S1 RB0
RC0
15
GND GND OSC1 13 C1 22pF
12 31
OSC2 14 XTAL1 20MHz
C2 22pF
Try to press a swtich at RB0/INT pin for making the external interrupt signal. LED at PORTC are turned on a few second after that they off because CPU return from interruptr service routine. The main program is controlling all LED at PORTC to off until the external interrupt is occured.
18 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void Delay_ms(unsigned int tick) { while(tick—) // Loop counter delay time { __delay_ms(1); // Delay 1 ms } } void interrupt INT_SERVICE(void) { if(INTF==1) // Ensure check INTF flag { PORTC ^= 0xFF; // Toggle LED at PORTC Delay_ms(10); // Delay a few time INTF = 0; // Clear INTF } } void main() { ANS12 = 0; // Set RB0 as digital port TRISB0 = 1; // Set RB0 input mode TRISC = 0; // Set PORTC as digital port PORTC = 0; // Ensure clear data of PORTC INTF = 0; // Ensure clear external interrupt flag INTE = 1; // Enable interrupt from INT/RB0 GIE = 1; // Enable global interrupt while(1); // Break program }
Listing L4-1 : interrupt_01.c; the experimental C code for PIC16F887’s external interrupt demonstration.
NX-887 Experiment documentation 19
PIC16F887 microcontroller Experiment Experiment 5 : Timer0 Experiment 5.1 : Timer0 timebase In this experiment is an example of programming to use Timer0 in timer mode with a second timer by checking TIF0 flag bit of Timer0. Every second, microcontroller will invert the LED status at RD0 pin. The experimental C code is shown in Listing L5-1.
Experimental circuit : +5V
11
C3 0.1F
IC1 PIC16F887
+5V R1 10k
32
R2 510
1
MCLR
19
RD0
SW1 RESET
12 31 13 C1 22pF
XTAL1 20MHz
14 C2 22pF
LED1 R1 390
20 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP unsigned int ms=0; // Keep Counter every 1 ms void main() { TRISD0 = 0; // Set RD0 output mode // Timer 0 Prescaler 1:128 PS0 = 0; PS1 = 1; PS2 = 1; PSA = 0; // Prescaler use for Timer 0 TMR0 = 216; // Initial value for Timer 0 T0CS = 0; // Use internal clock source while(1) // Infinite loop { if(T0IF==1) // Timer 0 overflow? { TMR0 = 216; // Reload value for Timer 0 T0IF = 0; // Clear Timer 0 overflow flag ms++; // Increase when 1 ms if(ms>=1000) // Up to 1 sec.? { ms=0; // Clear counter for next time RD0 =~RD0; // Toggle LED at RD0 } } } }
Listing L5-1 : timer0_01.c; the experimental C code for PIC16F887’s Timer0 demonstration.
NX-887 Experiment documentation 21
Experiment 5.2 : Timer0 interrupt This experiment demonstrates the examples of Timer0 interrupt operation. Timer0 generates the interrupt event every 1 millisecond. The interupt sevice routine will be store the value every time that interrupt is occured. Until value is equal 1 second, microcontroller will invert the logic status at RD0 pin to change the LED operation also display the current time value at LCD module screen. The experimental C code is shown in Listing L5-2.
Experimental circuit : +5V
11
C3 0.1F
IC1 PIC16F887
+5V R1 10k
32
R2 510
+5V
RD2 21
4
22
6
RD3 1
DSP1 LCD 16x2
RS E
Vo
MCLR
SW1 RESET
D7 D6 D5 D4 D3 D2 D1 D0 R/W 14 13 12 11 10 9 8 7 5
30
RD7
29
RD6
28
RD5
27
RD4
19
RD0
LED1 12 31 13 C1 22pF
+V
XTAL1 20MHz
14 C2 22pF
R1 390
GND 1
2 3 VR1 10k BRIGHTNESS
22 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU #include <lcd887.h> // Include Library for LCD display __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP unsigned int ms=0; // Keep Counter every 1 ms unsigned long sec=0; // Keep Counter every 1 sec void interrupt TIMER0_INT(void) { if(T0IF==1) { TMR0 = 216; T0IF = 0; ms++; if(ms>=1000) { ms=0; sec++; RD0 =~RD0; } } } void main() { lcd_init(); lcd_puts(0x80,”Counter=”); TRISD0 = 0; // Timer 0 Prescaler 1:128 PS0 = 0; PS1 = 1; PS2 = 1; PSA = 0; TMR0 = 216; T0IF = 0; T0IE = 1; GIE =1; T0CS = 0; while(1) { inttolcd(0x89,sec); } }
// Ensure check overflow flag // // // //
Reload value for Timer 0 Clear Timer 0 overflow flag Increase when 1 ms Up to 1 sec.?
// Clear counter for next time // Increase when 1 sec // Toggle LED at RD0
// Initial LCD // Show message at line 1 // Set RD0 output mode
// // // // // //
Prescaler use for Timer 0 Initial value for Timer 0 Ensure clear Timer 0 overflow flag Enable interrupt from Timer 0 Enable Global interrupt Use internal clock source
// Show counter sec. value
Listing L5-2 : timer0_02.c; the experimental C code for PIC16F887’s Timer0 interrupt demonstration.
NX-887 Experiment documentation 23
PIC16F887 microcontroller Experiment Experiment 6 : Timer1 Experiment 6.1 : Timer1 timebase This experiment demonstrate the simple operation of Timer1 to counts 1 millsecond to setting 1 second timebase by using test a TMR1F flag bit of Timer1. After the flag bit is set, increase the time register value. Until the value is equal 1 second, micorontroller will invert logic at RD0 pin. The LED at RD0 pin is connected to displays the result of operation. The experimental C code is shown in Listing L6-1.
Experimental circuit : +5V
11
C3 0.1F
IC1 PIC16F887
+5V R1 10k
32
R2 510
1
MCLR
19
RD0
LED1
SW1 RESET
12 31 13 C1 22pF
XTAL1 20MHz
14 C2 22pF
R1 390
24 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP unsigned int ms=0; // Keep Counter every 1 ms void main() { TRISD0 = 0; // Timer 1 Prescaler 1:1 T1CKPS0 = 0; T1CKPS1 = 0; TMR1CS = 0; TMR1H = 0xEC; TMR1L = 0x78; TMR1IF = 0; TMR1ON = 1; while(1) { if(TMR1IF==1) { TMR1H = 0xEC; TMR1L = 0x78; TMR1IF = 0; ms++; if(ms>=1000) { ms=0; RD0 =~RD0; } } }
// Set RD0 output mode
// Use internal clock source // Initial value for Timer 1 // Ensure clear Timer 1 overflow // Time 1 on // Infinite loop // Timer 1 overflow? // Reload value for Timer 1 // Clear Timer 1 overflow flag // Increase when 1 ms // Up to 1 sec.? // Clear counter for next time // Toggle LED at RD0
}
Code description Set Timer1 to counts and overflow every 1 millisecond. Timer1 counts from 0xEC78, 0xEC79, ..., 0xFFFF and back to 0. Total are 5000 counts. Each counting require 0.2 microsecond (from Fosc = 4/20000000 = 0.2 microsecond) Total time counting are 1000 microsecond or 1 millisecond. Every 1 millsecond, Timer1 is reloaded with 0xEC78 and increase value of ms register. After ms value as 1000 (it is 1 second), microcontrollere will be clear the ms value and invert logic status at RD0 pin.
Listing L6-1 : timer1_01.c; the experimental C code for PIC16F887 to use Timer 1 to create a simple timebase
NX-887 Experiment documentation 25
Experiment 6.2 : Timer1 interrupt This experiment is similar the experiment 5.2 but change from Timer0 interrupt to Timer1 interrupt. The result of operation is shown by LED at RD0 port. It is invert logic every second. By using Timer1 interrupt to generate timebase, it gives better performance and more flexible code development than the exmaple code in the experiment 6.1 (Listing L61). The experimental C code is shown in Listing L6-2.
Experimental circuit : +5V
11
C3 0.1F
IC1 PIC16F887
+5V R1 10k
32
R2 510
+5V
RD2 21
4
22
6
RD3 1
DSP1 LCD 16x2
RS E
Vo
MCLR
SW1 RESET
D7 D6 D5 D4 D3 D2 D1 D0 R/W 14 13 12 11 10 9 8 7 5
30
RD7
29
RD6
28
RD5
27
RD4
19
RD0
LED1 12 31 13 C1 22pF
+V
XTAL1 20MHz
14 C2 22pF
R1 390
GND 1
2 3 VR1 10k BRIGHTNESS
26 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU #include <lcd887.h> // Include Library for LCD display __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP unsigned int ms=0; // Keep Counter every 1 ms unsigned long sec=0; // Keep Counter every 1 sec void interrupt TIMER1_INT(void) { if(TMR1IF==1) // Timer 1 overflow? { TMR1H = 0xEC; // Reload value for Timer 1 TMR1L = 0x78; TMR1IF = 0; // Clear Timer 0 overflow flag ms++; // Increase when 1 ms if(ms>=1000)// Up to 1 sec.? { ms=0; // Clear counter for next time sec++; // Increase when 1 sec RD0 =~RD0; // Toggle LED at RD0 } } } void main() { lcd_init(); // Initial LCD lcd_puts(0x80,”Counter=”); // Show message at line 1 TRISD0 = 0; // Set RD0 output mode // Timer 1 Prescaler 1:1 T1CKPS0 = 0; T1CKPS1 = 0; TMR1CS = 0; // Use internal clock source TMR1H = 0xEC; // Initial value for Timer 1 TMR1L = 0x78; TMR1IF = 0; // Ensure clear Timer 1 overflow TMR1IE = 1; // Enable Timer 1 interrupt PEIE = 1; // Pheripheral interrupt enable GIE =1; // Enable Global interrupt TMR1ON = 1; // Time 1 on while(1) // Infinite loop { inttolcd(0x89,sec); // Show counter sec. value } }
Listing 6-2 : timer1_02.c; the experimental C code for PIC16F887 to use Timer1’s interrupt for making timebase
NX-887 Experiment documentation 27
PIC16F887 microcontroller Experiment Experiment 7 : Timer2 Experiment 7.1 : Timer2 timebase This experiment demonstrates the simple Timer2 operation to make 1 millisecond for inverting LED status every second at RD0 port. The experimental C code is shown in Listing L7-1.
Experimental circuit : +5V
11
C3 0.1F
IC1 PIC16F887
+5V R1 10k
32
R2 510
1
MCLR
19
RD0
LED1
SW1 RESET
12 31 13 C1 22pF
XTAL1 20MHz
14 C2 22pF
R1 390
28 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP unsigned int ms=0; // Keep Counter every 1 ms void main() { TRISD0 = 0; // Set RD0 output mode // Timer 2 Prescaler 1:4 T2CKPS0 = 1; T2CKPS1 = 0; // Timer 2 Postscaler 1:5 TOUTPS0 = 0; TOUTPS1 = 0; TOUTPS2 = 1; TOUTPS3 = 0; PR2 = 250; // Set Period Timer 2 TMR2ON = 1; // Time 2 on while(1) // Infinite loop { if(TMR2IF==1) // Timer 2 overflow? { TMR2IF = 0; // Clear Timer 2 overflow flag ms++; // Increase when 1 ms if(ms>=1000) // Up to 1 sec.? { ms=0; // Clear counter for next time RD0 =~RD0; // Toggle LED at RD0 } } } }
Code description Set Timer2’s prescaler as 1:4, postscaler as 1:5 and PR2 registor equal 250. Timer2 counts from 0 to 250. Each count require 0.8 microsecond. Calculate from 4/Fosc x 4 = (4/ 20000000) x 4 = 0.8 microsecond. Total time are 200 microsecond (0.8 x 250). Every 5 rounds, time is 1 millisecond. TMR2IF flag bit is set from postscaler operation and increase value of ms register. After ms value as 1000 (it is 1 second), microcontrollere will be clear the ms value and invert logic status at RD0 pin.
Listing L7-1 : timer2_01.c; the experimental C code for PIC16F887 to use Timer2 to create a simple timebase
NX-887 Experiment documentation 29
Experiment 7.2 : Timer2 interrupt This experiment is similar the experiment 5.2 and 6.2 but change from Timer0 (or Timer1) interrupt to Timer2 interrupt. The result of operation is shown by LED at RD0 port. It is invert logic every second. The experimental C code is shown in Listing L7-2.
Experimental circuit : +5V
11
C3 0.1F
IC1 PIC16F887
+5V R1 10k
32
R2 510
+5V
RD2 21
4
22
6
RD3 1
DSP1 LCD 16x2
RS E
Vo
MCLR
SW1 RESET
D7 D6 D5 D4 D3 D2 D1 D0 R/W 14 13 12 11 10 9 8 7 5
30
RD7
29
RD6
28
RD5
27
RD4
19
RD0
LED1 12 31 13 C1 22pF
+V
XTAL1 20MHz
14 C2 22pF
R1 390
GND 1
2 3 VR1 10k BRIGHTNESS
30 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU #include <lcd.h> // Include Library for LCD display __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP unsigned int ms=0; // Keep Counter every 1 ms unsigned long sec=0; // Keep Counter every 1 sec void interrupt TIMER2_INT(void) { if(TMR2IF==1) // Ensure check overflow flag { TMR2IF = 0; // Clear Timer 2 overflow flag ms++; // Increase when 1 ms if(ms>=1000) // Up to 1 sec.? { ms=0; // Clear counter for next time sec++; // Increase when 1 sec RD0 =~RD0; // Toggle LED at RD0 } } } void main() { lcd_init(); // Initial LCD lcd_puts(0x80,”Counter=”); // Show message at line 1 TRISD0 = 0; // Set RD0 output mode // Timer 2 Prescaler 1:4 T2CKPS0 = 1; T2CKPS1 = 0; // Timer 2 Postscaler 1:5 TOUTPS0 = 0; TOUTPS1 = 0; TOUTPS2 = 1; TOUTPS3 = 0; PR2 = 250; // Set Period Timer 2 TMR2IF = 0; // Ensure clear Timer 2 overflow flag TMR2IE = 1; // Enable interrupt from Timer 2 PEIE = 1; // Pheripheral interrupt enable GIE =1; // Enable Global interrupt TMR2ON = 1; // Time 2 on while(1) // Infinite loop { inttolcd(0x89,sec); // Show counter sec. value } }
Listing 7-2 : timer2_02.c; the experimental C code for PIC16F887 to use Timer2’s interrupt for making timebase
NX-887 Experiment documentation 31
PIC16F887 microcontroller Experiment Experiment 8 : CCP1 frequency counter This experiment demonstrates the application of PIC16F887’s CCP module; frequency counter. For this application, CCP1 module is set to Capture mode operation and works with Timer1. The frequency value is shown in Hz at LCD screen. The experimental C code is shown in Listing L8-1.
Experimental circuit : +5V
11
32
C3 0.1F
+5V R1 10k
IC1 PIC16F887
R2 510
1
MCLR
SW1 RESET
+5V
RD2 21
4
22
6
RD3
RS E
DSP1 LCD 16x2
+V Vo
Pulse /Function generator
30
RD7 OUT
GND 2
3 VR1 10k BRIGHTNESS
29
RD6
28
RD5
FREQUENCY
D7 D6 D5 D4 D3 D2 D1 D0 R/W 14 13 12 11 10 9 8 7 5
1
27
RD4 6 RC2/CCP1
12 31 13 C1 22pF
XTAL1 20MHz
14 C2 22pF
This experiment requires the variable pulse generator. The output signal is TTL level. Connect the input pulse to RC2/CCP1 pin and observe the operation at LCD module screen. Try to change the input signal frequency and see the result at LKCD module also.
32 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU #include <lcd887.h> // Include Library for LCD display #include <string.h> // Include Library for LCD display #include <stdio.h> // Include Library for LCD display #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP unsigned long freq=0; // Keep frequency detected char flag_capture = 0; // Keep status capture working void Delay_ms(unsigned int tick) { while(tick—) // Loop couter delay time { __delay_ms(1); // Delay 1 ms } } void interrupt CCP1_INT(void) { if(CCP1IF==1) // Rising edge detected? { CCP1CON = 0; // Disable capture module CCP1IF = 0; // Clear CCP1 interrupt flag TMR1ON = 0; // Time 1 off freq = 625000/((CCPR1H<<8)+CCPR1L); // Calculate frequency of signal flag_capture = 0; // Clear flag indicator } } void start_capture() { CCP1IE = 0; // Disable CCP1 interrupt TMR1H = 0x00; // Initial value for Timer 1 TMR1L = 0x00; CCP1IF = 0; // Clear CCP1 interrupt flag CCP1CON = 0x05; // Detect rising edge CCP1IF = 0; // Clear CCP1 interrupt flag while(CCP1IF==0); // Wait until rising edge detected flag_capture = 1; // Set flag indicator TMR1ON = 1; // Time 1 off CCP1IF = 0; // Clear CCP1 interrupt flag GIE =1; // Enable Global interrupt PEIE = 1; // Pheripheral interrupt enable CCP1IE = 1; // Enable CCP1 interrupt } void display_freq(unsigned char p,unsigned long f) { char freq_str[16]; // Keep string convert from frequency sprintf(freq_str,”%ld”,f); // Convert frequency to string strcat(freq_str,” Hz”); // Append string “ Hz” lcd_puts(p,freq_str); // Display message on module LCD } void main() { lcd_init(); // Initial LCD lcd_puts(0x80,”Freq:”); // Show message at line 1 // Timer 1 Prescaler 1:8 T1CKPS0 = 1; T1CKPS1 = 1; TMR1CS = 0; // Use internal clock source T1SYNC = 0; // Synchronize external clock input
Listing L8-1 : capture_01.c ; the experimental C code for using CCP1 module of PIC16F887 to counts the pulse signal frequency (continue)
NX-887 Experiment documentation 33
while(1) // Infinite loop { if(flag_capture==0) // Capture working? { lcd_puts(0x86,” “); // Clear old display value display_freq(0x86,freq); // Update frequency value start_capture(); // Start new capture Delay_ms(1000); // Delay 1 sec. for display } } }
Code description This code starts with initial LCD module. Next, set Timer1 operation. Set Timer1 prescaler as 1:8 in synchronous mode and detect the raising edge pulse. Program goes to loop while for checking flag_capture status. If it is “0”, means CCP1 ready for next detection and also displays the current frequency value at LCD screen under the interrupt service function ; CCP1_INT . If it is “1”, means CCP1 wait for pulse detection. The important function of this code includes : 1. start_capture : starts the capture operation of CCP1 module 2. display_freq : display the current frequency at LCD module 3. CCP1_INT : interrupt service routien for CCP1 module The frequency value is calculated from this relation :
Freq
1 4 FOSC
.................(1)
Pr escaler 8 CCPR1H CCPR1L
Therefore : Freq is the result frequency in Hertz Fosc is the microcontroller clock frequency Prescaler is Timer1 prescaler ratio CCPR1H is CCP1 high-byte value CCPR1L is CCP1 low-byte value From this experiment; Fosc = 20000000 and Presclaer = 8. Puts these parameter to formular.
Freq
Freq
1 4 8 8 CCPR1H CCPR1L 20 10 6 625000 8 CCPR1H CCPR1L
Listing L8-1 : capture_01.c ; the experimental C code for using CCP1 module of PIC16F887 to counts the pulse signal frequency (final)
34 NX-887
Experiment documentation
PIC16F887 microcontroller Experiment Experiment 9 : PWM generation There are 2 form ulas for PWM calculation of CCP module in PIC16F887 microcontroller. First is PWM frequencycalculation and another is PWM duty cycle calculation. PWM frequency formula :
FPWM
FOSC 4 PR2 1 T2 CKPS_ set
............................(1)
therefore : FPWM is PWM signal frequency in Hertz FOSC is the microcontroller clock frequency PR2 is PR2 register value T2CKPS_set is Timer2 prescaler value. It is defined from T2CKPS1 and T2CKPS0 bit of T2CON register. There are 3 values as follows : T2CKPS_set = 1 when T2CKPS[1:0] = 00 T2CKPS_set = 4 when T2CKPS[1:0] = 01 T2CKPS_set = 16 when T2CKPS[1:0] = 1x (x will be “0” or “1”) PWM duty cycle formula :
PWM duty cycle =
CCPRxL, DCxB1, DCxB0 .........................(2) 4 PR2 1
therefore : CCPRxL is 8-bit value of CCPR1L or CCPR2L register DCxB1 is bit 5 value of CCP1CON or CCP2CON register DCxB0 is bit 4 value of CCP1CON or CCP2CON register PR2 is PR2 register value Must collect the value of CCPRxL, DCxB1 and DCxB0 to 10-bit data. Bit 7 of CCPRxL is assigned to MSB bit.
NX-887 Experiment documentation 35
ZX-DCM2 : 2-ch. DC motor driver board Use L293D H-bridge driver IC. Drives 2 motors +6 to +12V for motor supply voltage Require 3 signal lines for motor control Motor supply voltae indicator Screw-terminal block for motor connection
+VM DC motor supply voltage terminal (+6 to +12V 1A)
2B 2A 2E G
DIR2B
DIR1B
DIR1A
+VM
DIR2A
Connect with the digital output port for direction control of Motor ch-2
1B 1A 1E +5
PWM2 2E
Connect PWM signal for speed control of Motor ch-2
PWM1 1E
+ Connect PWM signal for speed control of Motor ch-1 Connect with the digital output port for direction control of Motor ch-1
Motor supply voltage indicator OUT2
+ DC motor ch-2 terminal
OUT1
+ DC motor ch-1 terminal
* 6V DC motor is recommended for this driver board
This experiment demonstrates the PWM generation of PIC16F887. PWM signal from CCP1 and CCP2 module is used for DC motor speed control. The DC motor driver board is required for this experiment. ZX-DCM board is recommended. (see details in www.inexglobal.com). The experimental C code is shown in Listing L9-1.
36 NX-887
Experiment documentation
Experimental circuit : K18A-K18B MOTOR-A
INVERT
+5V C7 0.1 F 50V
+5V +Vm 11 +5V R1 10k
32
C5 0.1F 50V
IC1 PIC16F887 R2 510
RD0 1
MCLR
SW1 RESET
RD1
2
20
7 2A
RB2 RC1/CCP2
1
8
Vcc1
19
RC2/CCP1 17 RB1
16
1Y 3
1A
12EN
34
15 4A
35
10
16
9
2Y
+
R9 2k2
DIRECT LED3 DIR. #A
6
14 IC3 4Y L293D 11 3Y
LED4 DIR. #B
R10 2k2
3A
INVERT
34EN
+
C8 0.1 F 50V
12 31
+
13 12 5
4
+ K19A-K19B MOTOR-B
DIRECT
Motor Driver 13 C1 22pF
XTAL1 20MHz
14 C2 22pF
Both DC motors are driven in forward direction 2 seconds and backward in 2 seconds. The direction LED indicates direction. In forward, they must be green and change to red color in backward direction. If incorrect, must change the motor wire connection.
NX-887 Experiment documentation 37
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void Delay_ms(unsigned int tick) { while(tick—) // Loop couter delay time { __delay_ms(1); // Delay 1 ms } } void main() { ANS8 = 0; // Set RB2 digital port ANS10 = 0; // Set RB1 digital port TRISB1 = 0; // Set RB1 output mode TRISB2 = 0; // Set RB2 output mode TRISD0 = 0; // Set RD0 output mode TRISD1 = 0; // Set RD1 output mode TRISC1 = 0; // Set RC1 output mode TRISC2 = 0; // Set RC2 output mode CCP1CON = 0x0C; // CCP1 PWM mode CCP2CON = 0x0C; // CCP2 PWM mode PR2 = 0xFF; // Set Period counting TMR2IF =0; // Ensure Clear overflow flag timer2 T2CON |= 0x01; // Prescaler 4 T2CON |= 0x04; // Start timer2 CCP1CON |= 0x30; // CCP1 PWM mode CCP2CON |= 0x30; // CCP2 PWM mode CCPR1L = 100; // Set duty for CCP1 40% CCPR2L = 190; // Set duty for CCP2 75% while(1) { // Set direction for drive motor A and B RD0 = 0; RD1 = 1; RB1 =0; RB2 =1; Delay_ms(2000); // Drive motor 2 sec. // Invert direction for drive motor A and B RD0 = 1; RD1 = 0; RB1 =1; RB2 =0; Delay_ms(2000); // Drive motor 2 sec. } }
Listing L9-1 : pwm_01.c ; the experimental C code for PIC16F887 to generates the PWM signal to control DC motor from CCP1 and CCP2 module.
38 NX-887
Experiment documentation
PIC16F887 microcontroller Experiment Experiment 10 : Enhanced PWM Experiment 10.1 : Single output This experiment demonstrates the CCP1 operation to generate PWM signal in Enhanced operation with single output mode at P1A and P1B output pins of PIC16F887. The experimental C code is shown in Listing L10-1.
Experimental circuit : +5V 11 +5V R1 10k
32
C5 0.1F 50V
IC1 PIC16F887 R2 510
1
MCLR
SW1 RESET
RC2/P1A 17 RD5/P1B
28
12 31 13 C1 22pF
XTAL1 20MHz
14 C2 22pF
Connect with oscilloscope to measure PWM signal at these pins
NX-887 Experiment documentation 39
#include <pic.h> // Include header file for MCU __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void main() { // Enhanced PWM Single output STRA = 1; // Use P1A(RC2 pin)generate PWM output signal STRB = 1; // Use P1B(RD5 pin)generate PWM output signal TRISC2 = 0; // Set RC2 output mode TRISD5 = 0; // Set RD5 output mode CCP1CON = 0x0C; // CCP1 PWM mode,CCP1M3:CCP1M0=1100,P1M1:P1M0=00 PR2 = 0xFF; // Set Period counting TMR2IF =0; // Ensure Clear overflow flag timer2 T2CON |= 0x01; // Prescaler 4 T2CON |= 0x04; // Start timer2 CCP1CON |= 0x30; // CCP1 PWM mode CCPR1L = 100; // Set duty for CCP1 40% while(1); // Break program }
Listing L10-1 : pwm_02.c ; the experimental C code for CCP1 module of PIC16F887 to generates the Enhanced PWM signal in Single output mode
40 NX-887
Experiment documentation
Experiment 10.2 : Half-bridge mode This experiment demonstrates the CCP1 operation to generate Enhanced PWM signal in Half-bridge mode at P1A and P1B output pins of PIC16F887. The PWM signal of each pin are 180 degree different. The experimental C code is shown in Listing L10-2.
Experimental circuit : Same in the experiment 10.1 The PWM output signals are shown in the picture below.
#include <pic.h> // Include header file for MCU __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void main() { // Enhanced PWM Half-Bridge STRA = 1; // Use P1A(RC2 pin)generate PWM output signal STRB = 1; // Use P1B(RD5 pin)generate PWM output signal TRISC2 = 0; // Set RC2 output mode TRISD5 = 0; // Set RD5 output mode PWM1CON |= 0x3F; // Delay time 12.6 us CCP1CON = 0x8C; // CCP1 PWM mode,CCP1M3:CCP1M0=1100,P1M1:P1M0=10 PR2 = 0xFF; // Set Period counting TMR2IF =0; // Ensure Clear overflow flag timer2 T2CON |= 0x01; // Prescaler 4 T2CON |= 0x04; // Start timer2 CCP1CON |= 0x30; // CCP1 PWM mode CCPR1L = 100; // Set duty for CCP1 40% while(1); }
Listing L10-2 : pwm_03.c ; the experimental C code for CCP1 module of PIC16F887 to generates the Enhanced PWM signal in Half-bridge mode
NX-887 Experiment documentation 41
Experiment 10.3 : Full-Bridge Forward mode This experiment demonstrates the CCP1 operation to generate Enhanced PWM signal in Full-bridge Forward mode at only P1D and P1A output pins of PIC16F887 with active logic “1”. The experimental C code is shown in Listing L10-3.
Experimental circuit : +5V 11 +5V R1 10k
32
C5 0.1F 50V
IC1 PIC16F887 R2 510
1
MCLR
SW1 RESET
RC2/P1A 17 RD5/P1B RD6/P1C RD7/P1D
28 29 30
Connect with oscilloscope to measure PWM signal at these pins
12 31 13 C1 22pF
XTAL1 20MHz
14 C2 22pF
#include <pic.h> // Include header file for MCU __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void main() { // Enhanced PWM Full-Bridge Forward STRA = 1; // Use P1A(RC2 pin)generate PWM output signal STRB = 1; // Use P1B(RD5 pin)generate PWM output signal STRC = 1; // Use P1C(RD6 pin)generate PWM output signal STRD = 1; // Use P1D(RD7 pin)generate PWM output signal TRISC2 = 0; // Set RC2 output mode TRISD5 = 0; // Set RD5 output mode TRISD6 = 0; // Set RD6 output mode TRISD7 = 0; // Set RD7 output mode PWM1CON |= 0x3F; // Delay time 12.8 us CCP1CON = 0x4C; // CCP1 PWM mode,CCP1M3:CCP1M0=1100,P1M1:P1M0=01 PR2 = 0xFF; // Set Period counting TMR2IF =0; // Ensure Clear overflow flag timer2 T2CON |= 0x01; // Prescaler 4 T2CON |= 0x04; // Start timer2 CCP1CON |= 0x30; // CCP1 PWM mode CCPR1L = 100; // Set duty for CCP1 40% while(1); }
Listing L10-3 : pwm_04.c ; the experimental C code for CCP1 module of PIC16F887 to generates the Enhanced PWM signal in Full-bridge Forward mode
42 NX-887
Experiment documentation
The output signal at P1A and P1B of PIC16F887 are
The output signal at P1C and P1D of PIC16F887 are
NX-887 Experiment documentation 43
Experiment 10.4 : Full-Bridge Reverse mode This experiment demonstrates the CCP1 operation to generate Enhanced PWM signal in Full-bridge Reverse mode at only P1B and P1C output pins of PIC16F887 with active logic “1”. The experimental C code is shown in Listing L10-4.
Experimental circuit : Same in the experiment 10.3 The output signal at P1A and P1B of PIC16F887 are
The output signal at P1C and P1D of PIC16F887 are
44 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void main() { // Enhanced PWM Full-Bridge Reverse STRA = 1; // Use P1A(RC2 pin)generate PWM output signal STRB = 1; // Use P1B(RD5 pin)generate PWM output signal STRC = 1; // Use P1C(RD6 pin)generate PWM output signal STRD = 1; // Use P1D(RD7 pin)generate PWM output signal TRISC2 = 0; // Set RC2 output mode TRISD5 = 0; // Set RD5 output mode TRISD6 = 0; // Set RD6 output mode TRISD7 = 0; // Set RD7 output mode PWM1CON |= 0x3F; // Delay time 12.6 us CCP1CON = 0xCC; // CCP1 PWM mode,CCP1M3:CCP1M0=1100,P1M1:P1M0=11 PR2 = 0xFF; // Set Period counting TMR2IF =0; // Ensure Clear overflow flag timer2 T2CON |= 0x01; // Prescaler 4 T2CON |= 0x04; // Start timer2 CCP1CON |= 0x30; // CCP1 PWM mode CCPR1L = 100; // Set duty for CCP1 40% while(1); // Break program }
Listing L10-4 : pwm_05.c ; the experimental C code for CCP1 module of PIC16F887 to generates the Enhanced PWM signal in Full-bridge Reverse mode
NX-887 Experiment documentation 45
PIC16F887 microcontroller Experiment Experiment 11 : ADC module in PIC16F887 This experiment demonstrates the Analog to Digital Converter module of PIC16F887 operation. It reads analog signal at RA2 pin. The conversion data will be displayed at LCD module screen. The experimental C code is shown in Listing L8-1.
Experimental circuit : +5V
11
32
C3 0.1F
+5V R1 10k
R2 510
IC1 PIC16F887 1
+5V
RD2 21
4
22
6
MCLR RD3
SW1 RESET
RS E
DSP1 LCD 16x2
+V Vo
+5V VR1 10k
30
RD7 R2 150
29
RD6
4
AN2/RA2
28
RD5
27
RD4
12 31 13 C1 22pF
XTAL1 20MHz
14 C2 22pF
D7 D6 D5 D4 D3 D2 D1 D0 R/W 14 13 12 11 10 9 8 7 5
GND 1
2 3 VR1 10k BRIGHTNESS
46 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU #include <lcd.h> // Include Library for LCD display __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void main() { int adc=0; // Keep ADC value TRISA2 = 1; // Set RA2 input mode ANS2 = 1; // Set RA2 analog port ADCON0 = 0b11001001; // Select RC Mode,ANS2 active,ADON=1 lcd_init(); // Initial LCD lcd_puts(0x80,”ADC(RA2)=”); // Show message at line 1 while(1) // Infinite loop { GODONE = 1; // Start conversion while(GODONE); // Wait until conversion success adc = (ADRESH<<2)+(ADRESL>>6); // Get ADC value lcd_puts(0x89,” “); // Clear old value inttolcd(0x89,adc); // Update new value delay(100); // Delay a few time for display } }
Listing L11-1 : adc_01.c ; the experimental C code for PIC16F887 ADC module demonstration
NX-887 Experiment documentation 47
PIC16F887 microcontroller Experiment Experiment 12 : Analog comparator Experiment 12.1 : simple operation of analog comparator module This experiment demonstrates the simple operation of PIC16F887’s analog comparator module ch-1 or C1. Choose the RA1/C12IN1-port as Vin- input. Reference voltage is 3.125V from the internal reference voltage module; CVREF by connected with Vin+ input. Comparator output is RA4/C1OUT port that connect with LED to shows the operation. The experimental C code is shown in Listing L12-1.
Experimental circuit : +5V +5V 11 R1 10k
R2 510
1
32
C3 0.1F
MCLR
SW1 RESET
IC1 PIC16F887 6
RA4/C1OUT
LED1
+5V VR1 10k
R3 150
12 4
R1 390
RA1/C12IN1- 31
13 C1 22pF
XTAL1 20MHz
14 C2 22pF
Try to adjust the applying voltage at RA1 pin. Observe the LED operation at RA4/ C1OUT pin. In case RA1 voltage is lower than 3.125V, RA4’s LED is turned on because the internal reference voltage is higher than the external voltage at Vin- input or RA1/C12IN1-. In the other hand, when RA1 voltage is equal or higher than 3.125V, the analog comparator will be active. Output is low. It cause RA4 logic as “0”. LED is off.
48 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void main() { ANS1 = 1; // Set RA1 analog pin TRISA1 = 1; // Set RA1(C12IN1- pin)input mode TRISA4 = 0; C1R = 1; C1CH0 = 1; C1CH1 = 0; C1OE = 1; C1RSEL = 1; VRCON = 0xAF; VDD) C1ON = 1; while(1);
// Set RA4(C1OUT) output mode // C1VIN+ connects to C1VREF output // Select C12IN1- pin of C1 connects to C1VIN// C1OUT is present on the C1OUT pin // Set CVREF by program // Config. 3.125V reference(CVREF = (VR<3:0>/24)x // Enable Comparator C1 // Break program
}
Code descritption This program starts with set RA1 as analog input and connect to Vin- pin of analog comparator module and assign RA4/C1OUT as output of comparator Example C code for enabling the analog comparator module is shown below : C1R = 1; // voltage output ; C1VREF C1CH0 = 1; // with C1VIN- pin C1CH1 = 0; C1OE = 1; // C1RSEL = 1; // module - C1 VRCON = 0xAF; // set the reference voltage C1ON = 1; // while(1); //
Set C1VIN+ to connect with the internal reference Define
C12IN1- of comparator module ; C1 to connect
Choose C1OUT connect with RA4/C1OUT pin Connect CVREF with C1VREF for analog comparator Choose low range of internal reference voltage and at Vin+ pin as 3.125V Enable the comparator module - C1 Break program
The internal reference voltage at Vin+ pin in this experiemnt is calculated from : Reference voltage = (VR10/24) x CVRSRC Choose the reference voltage in low range from setting the VRR bit of VRCON register and CVRSRC voltage as +5V foloowing the supply voltage. Define VR value as 15 in decimal number. It causes the reference voltage is equal to (15/24) x 5 = 3.125V
Listing L12-1 : comparator_01.c ; the experimental C code for testing the analog comparator module of PIC16F887
NX-887 Experiment documentation 49
Experiment 12.2 : Anlog comparator interrupt In this experiment presents how to use thge analog comparator by using interrupt. Assign the RA1/C12IN1- as Vin- input pin, Vin+ input connect with internal reference voltage (CVREF) that is equal 3.125V. The output of comparator is RA4/C1OUT pin. Everytime that comparator is activated, the output status is changed. The interrupt is occured. CPU will be jump to execute the analog comparator interrupt service routine. The experimental C code is shown in Listing L12-2.
Experimental circuit : +5V
11
32
C3 0.1F
+5V R1 10k
R2 510
IC1 PIC16F887 1
MCLR
SW1 RESET
VR1 10k
R3 150
19
RD0 4
R1 390
LED2
R1 390
6
RA4/C1OUT
+5V
LED1
RA1/C12IN112 31 13
C1 22pF
XTAL1 20MHz
14 C2 22pF
(1) Try to apply voltage at RA1 pin lower 3.125V. Observe the LED operation at RA4/C1OUT and RD0 pin. In case RA1 voltage is lower than 3.125V, the analog comparator will set logic “1” at output. LED at RA4 pin is on but LED at RD0 is still off. (2) Increase RA1 voltage higher than 3.125V. Observe the LED operation at RA4/ C1OUT and RD0 pin. When RA1 voltage is higher than 3.125V, LED at RD0 is on and LED at RA4 pin is offf because the reference voltage is lower than the external input voltage at Vin- pin of the angalog comparator that is connected with RA1 pin. The LED operation of RD0 pin is controlled by interrupt service routine everytime that comparator output status is changed. The interrupt is occured when Vin- voltage is equal to the reference voltage at Vin+ pin of analog comparator module.
50 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void interrupt C1OUT_SERVICE(void) { if(C1IF==1) // Ensure check C1IF flag { C1IF = 0; // Clear C1IF RD0 =~RD0; // Toggle LED at RD0 } } void main() { ANS1 = 1; // Set RA1 analog pin TRISA1 = 1; // Set RA1(C12IN1- pin)input mode TRISA4 = 0; // Set RA4(C1OUT) output mode TRISD0 = 0; // Set RD0 output mode C1R = 1; // C1VIN+ connects to C1VREF output C1CH0 = 1; // Select C12IN1- pin of C1 connects to C1VINC1CH1 = 0; C1OE = 1; // C1OUT is present on the C1OUT pin C1RSEL = 1; // Set CVREF by program VRCON = 0xAF; // Config. 3.125V reference(CVREF = (VR<3:0>/24)*VDD) C1IF = 0; // Ensure clear interrupt flag PEIE = 1; // Pheripheral interrupt enable C1IE = 1; // Enable C1 interrupt GIE = 1; // Enable Global interrupt C1ON = 1; // Enable Comparator C1 while(1); // Break program }
Code descritption This program starts with set RA1 as analog input and connect to Vin- pin of analog comparator module and assign RA4/C1OUT as output of comparator and RD0 pin as interrupt monitoring output. The interrupt service function ; C1OUT_SERVICE works as follows : void interrupt C1OUT_SERVICE(void) { if(C1IF==1) // Make sure the interrupt requesting is from Analog comparator module - C1 { C1IF = 0; // Clear interrupt flag RD0 =~RD0; // Invert RD0 logic status } }
Listing L12-2 : comparator_02.c ; the experimental C code for testing the analog comparator module interrupt
NX-887 Experiment documentation 51
PIC16F887 microcontroller Experiment Experiment 13 : EUSART (Enhanced UART) Experiment 13.1 : Simple serial communication This experiment demonstrates an example of C programming to send and receive data through the PIC16F887’s EUSART module with the serial port of computer by using Hyper Terminal. PIC16F887 wait the keyboard pressing data at HyperTerminal. After getting the data, microcontroller will send echo same character to the terminal program. The serial dta must be ASCCII format. The experimental C code is shown in Listing L13-1.
Experimental circuit : +5V +5V
+5V C5 10/50V
16
C6 10/50V 1
6 7 8
1 2 3 4 5
K1 SERIAL PORT
C4 10/50V
3
R2 510
IC1 PIC16F887 1
5
C7 10/50V
10
TxD
25
8
9
RxD
26
GND
12
6
15
MCLR
4
7
C8 10/50V
32
11
SW1 RESET
2
IC2 MAX232
R1 10k
C3 0.1/50V
RC6/TxD RC7/RxD
SK1 SERIAL DATA
OSC1 13 C1 22pF
OSC2 14
X1 20MHz
C2 22pF
52 NX-887
Experiment documentation
The computor requirement of this experiment is one serial port. If not, must require USB to RS-232 serial port converter. UCON-232S is recommended (See details at www.inex.co.th). (1) Before testing; open the Hyper Terminal and set the properties as follows : Baudrate : 9600 bit per second Data format : 1 stop bit, no parity and 8-bit data (2) Connect the RS-232 output circuit to computer’s serial port (directly or through USB to RS-232 converter) After program running, at the Hyper Terminal screen shows Press keyboard for test Echo! message following the picture below
(3) Try to press numerical key - 1. Hyper Terminal shows message : You Press Key: 1 reports microconttroller get key number 1 from computer via serial port communication and send the same character back to computer. Try with another numerical keys and character keys
NX-887 Experiment documentation 53
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void Delay_ms(unsigned int tick) { while(tick—) // { __delay_ms(1); // } } void usart_init() // { SYNC = 0; BRGH = 1; BRG16 = 1; SPBRG = 0x08; SPBRGH = 0x02; TXEN = 1; // CREN = 1; // SPEN = 1; // } void usart_putc(unsigned char c) { while(!TRMT); // TXREG = c; // } void usart_puts(unsigned char *s) { while(*s) // { usart_putc(*s++); // } } unsigned char usart_getc() { while(!RCIF); // return(RCREG); // } void main() { unsigned char key; // usart_init(); // usart_puts(“Press keyboard for test while(1) // { key = usart_getc(); // // Echo message usart_puts(“You press key:”); usart_putc(key); usart_puts(“\r\n”); } }
Loop couter delay time Delay 1 ms
Set buadrate 9600 bps
Enable transitions Enable receive Enable USART transitions/receive
Wait transitions ready Send byte
Loop for send string Send byte from string
Wait data receive Return data
Keep data receive from keyboard Initial USART baudrate 9600 bps Echo!\r\n”); // Display first message Infinite loop Wait until data receive
Listing L13-1 : usart_01.c ; the experimental C code for PIC16F887 EUART module demonstration (continue)
54 NX-887
Experiment documentation
Code descritption This program starts with set the USART properties with usart_init function and send message ; Press keyboard for test Echo! to computer by using usart_puts function. After that program goes to loop whiles for checking the recieving data by usart_getc function. After getting the character, microcontroll returns by usart_putc function. The important C function of this experiment code includes 1. usart_init : set all important parameter of EUSART 2. usart_putc : send 1-byte data to EUSART transmitter 3. usart_puts : send string to EUSART transmitter 4. usart_getc : receive data from EUSART receiver
Listing L13-1 : usart_01.c ; the experimental C code for PIC16F887 EUART module demonstration (final)
Experiment 13.2 : EUSART interrupt The operation of this experiment is similar the previous exepriment. Changing is only method. In this experiment use the interrupt of EUSART module to setting the serial data communication. The benefit of this operation is do not loop to wait the incoming data. MIcrocontroller can execute another instructions. When incoming dara is appeared, the interrupt is occured. Microcontroller jumps to get the incoming data by using interrupt servicec routine. The experimental C code is shown in Listing L13-2.
Experimental circuit : Same the expeirment 13.1 Also set the properties of Hyper terminal program and make hardware connection same the experiment 13.1. The operation of EUSART interrupt service routine of this experiment; USART_ RC_SERVICE described below void interrupt USART_RC_SERVICE(void) { if(RCIF) // Check the interrupr flag bit is set, or not ? { usart_puts(“You press key:”); // If set, send message back to computer usart_putc(RCREG); // Send the received character to computer usart_puts(“\r\n”); // Send the carriage return control char. // to computer } }
NX-887 Experiment documentation 55
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void Delay_ms(unsigned int tick) { while(tick—) { __delay_ms(1); } } void usart_init() { // Set buadrate 9600 bps SYNC = 0; BRGH = 1; BRG16 = 1; SPBRG = 0x08; SPBRGH = 0x02; TXEN = 1; CREN = 1; SPEN = 1; } void usart_putc(unsigned char c) { while(!TRMT); TXREG = c; } void usart_puts(unsigned char *s) { while(*s) { usart_putc(*s++); } } void interrupt USART_RC_SERVICE(void) { if(RCIF) { //Echo usart_puts(“You press key:”); usart_putc(RCREG); usart_puts(“\r\n”); } } void main() { unsigned char key; usart_init(); RCIE =1; GIE = 1; PEIE = 1; usart_puts(“Press keyboard for test while(1); }
// Loop couter delay time // Delay 1 ms
// Enable transition // Enable receive // Enable USART transition/receive
// Wait transition ready // Send byte
// Loop for send string // Send byte from string
// Ensure check RCIF flag
// Keep data receive from keyboard // Initial USART baudrate 9600 bps // Enable receive interrupt // Enable global interrupt // Enables peripheral interrupts Echo!\r\n”); // Display first message // Infinite loop
Listing L13-2 : usart_02.c ; the experimental C code for PIC16F887 EUART module interrupt demonstration
56 NX-887
Experiment documentation
PIC16F887 microcontroller Experiment Experiment 14 : Interface with MCP4922 Digital-to-Analog Converter IC by using SPI module This experiment demonstrates the example of using SPI module of PIC16F887 to interface with DAC integrated circuit; MCP4922. PIC16F887 send the digital data to MCP4922 for converting to analog voltage. The output voltage increase 2 times every 3 seconds.
MCP4922 features 12-bit conversion resolution 2-analog output. Support single output operation Interface via SPI bus. Maximum clock frequency is 20MHz Latch output enable +2.7 to +5.5V supply voltage
The pin assignment of MCP4922 and details of control register are shown below.
VDD 1
SCK 4 SDI 5
บิต 13
บิต 12
บิต 11
บิต 10
บิต 9
บิต 8
A/B
BUF
GA
SHDN
D11
D10
D9
D8
W -x
W -x
W -0
W -x
W -x
W -x
W -x
12 AVss
บิต 7
บิต 6
บิต 5
บิต 4
บิต 3
บิต 2
บิต 1
บิต 0
11 VREFB
D7
D6
D5
D4
D3
D2
D1
D0
W -x
W -x
W -x
W -x
W -x
W -x
W -x
W -x
13 VREFA
MCP4922
CS 3
บิต 14
W -x
14 VOUTA
NC 2
บิต 15
10 VOUTB
NC 6
9 SHDN
NC 7
8 LDAC
Bit 15 - A/B (DACA/DACB select bit) : “0” = Write data to DACA “1” = Write data to DACB Bit 14 - BUF (VREF Input Buffer Control bit) “0” = Not use buffer “1” = Enable buffer Bit 13 - GA (Output Gain Select bit) “0” = Enable. Output voltage is equal 2 x VREF x digital data/4096 “1” = Disable. Output voltage is equal VREF x digital data/4096 Bit 12 - SHDN (Output Power Down Control bit) “0” = Disable “1” = Enable Bit 0 to 11 - D0 to D11 (DAC Data bits) : 12-bit digital data
NX-887 Experiment documentation 57
Illustration below is timing diagram of MCP4922 operation.
CS 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
D3
D2
D1
D0
SCK control bit
SDI
A/B
BUF
GA
SHDN
12-bit data D11
D10
D9
D8
D7
D6
D5
D4
LDAC
Vout
Output voltage
MCP4922 has only a control register. It is WRTE COMMAND register. Refer the timing diagram above, interfacing starts with send logic “0” to CS pin following apply clock to SCK pin. Next, writes 4-bit config data follows 12-bit data for conversion. During writing data must maintain the LDAC pin status as logic “1”. After that change logic at LDAC as “0” and CS pin as “1”. Analog voltage will be appeared at Vout pin.
How to use PIC16F887’s SPI module with MCP4922 For interfacing with MCP4922, PIC16F887 must be set the idle clokc of SPI module as logic “0” and active at raising edge of clock because MCP4922 active when CS pin logic staus is “0”. Must clear and set bit CKP and CKE in SPI module respectively. Set the SPI clock as FOSC/16 or 1.25 MHz at 20MHz crystal clock. The experimental C code is shown in Listing L14-1.
58 NX-887
Experiment documentation
Experimental circuit : +5V
1
+5V R1 10k
+5V
11 R2 510
32
VDD IC2 MCP4922
IC1 PIC16F887 1
MCLR
SW1 RESET
RC0 15 RC3/SCK 18 RC5/SDO 24
VREFB 11 13 VREFA
3 CS 4 SCK 9 5 SDI SHDN 14 VOUTA 8 LDAC VOUTB
OSC1 13 C1 22pF
OSC2 14 XTAL1 20MHz
10
DC outputA DC outputB
VSS 12 C2 22pF
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP #define A_B1_G1 0x70 // Channel A Buffered x1 Gain #define A_B1_G2 0x50 // Channel A Buffered x2 Gain #define A_B0_G1 0x30 // Channel A nonBuffered x1 Gain #define A_B0_G2 0x10 // Channel A nonBuffered x2 Gain #define B_B1_G1 0xF0 // Channel B Buffered x1 Gain #define B_B1_G2 0xD0 // Channel B Buffered x2 Gain #define B_B0_G1 0xB0 // Channel B nonBuffered x1 Gain #define B_B0_G2 0x90 // Channel B nonBuffered x2 Gain #define SHDN 0x00 // Channel A and B Output High Impedance void Delay_ms(unsigned int tick) { while(tick—) // Loop couter delay time { __delay_ms(1); // Delay 1 ms } } void spi_init() { PORTC = 0x00; // Ensure clear data PORTC TRISC0 = 0; // Set output for CS pin TRISC3 = 0; // Set output for SCK pin TRISC5 = 0; // Set output for SDO pin CKE = 1; // First edge/Rising edge SSPCON = 0x01; // Fosc/16,Idle clock low SSPEN = 1; // Enable master }
Listing L14-1 : spi_01.c ; the experimental C code for PIC16F887 interfacing with MCP4922 DAC device via SPI bus (continue)
NX-887 Experiment documentation ď Źď&#x20AC; 59
void spi_write(unsigned char dat) { SSPBUF = dat; // Send data byte while(!BF); // Wait until send complete } void dac_out(char config,unsigned int output) { RC0 = 0; // CS=0 spi_write(config+(output>>8)); // Send High byte spi_write(output&0xFF); // Send Low byte RC0 = 1; // CS=1 } void main() { char i; // Keep counter unsigned int vout; // Keep data output spi_init(); // Initial SPI module RC0 = 1; // CS=1 dac_out(SHDN,0); // A and B Output High Impedance while(1) // Infinite loop { for(i=0;i<13;i++) // Loop for counter { vout=(1<<i)-1; // Double data output dac_out(A_B0_G1,vout); // Set output for channel A dac_out(B_B0_G1,vout); // Set output for channel B Delay_ms(3000); // Delay 3 sec. } } }
Code descritption This program starts with set the SPI module properties with spi_init function and program goes to loop while{} for writing data to define the output voltage at channel A and B of MCP4922 with dac_out function every 3 seconds. The important C function of this experiment code includes 1. spi_init : Set all parameters for using SPI module of PIC16F887 2. spi_write : Write 1-byte data to SPI bus 3. dac_out : Write 2-byte data to MCP4922 via SPI bus
Listing L14-1 : spi_01.c ; the experimental C code for PIC16F887 interfacing with MCP4922 DAC device via SPI bus (final)
60 NX-887
Experiment documentation
PIC16F887 microcontroller Experiment Experiment 15 : Interface with MCP23016 I/O expander via I2C bus This experiment demonstrates the example of using I2C bus of PIC16F887 to interface with I/O expander device; MCP23016. The key of programming is i2c887.h library file. This experiment is 8-bit output expansion to control 8-LED at GP0.0 to GP0.7 pin fo MCP23016. Lising L15-1 is sourcecode of the i2c887.h library file. Requires to includes at the head of program. The hardware connection definition are : SDA pin as RC4 of PIC16F887 and SCL pin as RC3 of PIC16F887
Function description of i2c887.h library 1. i2c_init Initial the MSSP module to I2C bus mode Syntax
void i2c_init()
2. i2c_start Define the START condition for I2C bus Syntax
void i2c_start()
3. i2c_stop Define the STOP condition for I2C bus Syntax
void i2c_stop()
4. i2c_write Write 1-byte data to I2C bus device Syntax
char i2c_write(unsigned char dat) Parameter dat : 1-byte data Return value “1” when the slave device acknowledge “2” when no acknowledge from slave device
NX-887 Experiment documentation 61
//——————————————————————————————————————————// // Program : Library for i2c bus // Description : Library for i2c bus // Frequency : Crystal 20 MHz // Filename: i2c887.h // C compiler : Hitech C Compiler //——————————————————————————————————————————// #ifndef _I2C_H_ #define _I2C_H_ #include <pic.h> // Include header file for MCU #define ACK1 // Macro for used acknowledge in i2c_read function #define NACK 0 // Macro for not used acknowledge in i2c_read function //——————————— Function void i2c_start() { SEN = 1; // while(!SSPIF); // SSPIF = 0; // }
i2c start condition
———————————//
Start I2C Wait for start complete Clear flag
//——————————— Function i2c stop condition ———————————// void i2c_stop() { PEN = 1; // Stop I2C while(!SSPIF); // Wait for stop complete SSPIF = 0; // Clear flag } //——————————— Function i2c write data ——————————————// char i2c_write(unsigned char dat) { SSPBUF = dat; // Send data while(!SSPIF); // Wait for send data complete SSPIF = 0; // Clear flag if(ACKSTAT) // Check ACK signal from slave { i2c_stop(); // When slave not connected return(2); } else { return(1); // When slave connected } } //——————————— Function i2c read data ——————————————// unsigned char i2c_read(char check) { unsigned char dat; // Keep data RCEN = 1; // Receive enable while(!SSPIF); // Wait for receive complete SSPIF = 0; // Clear flag dat = SSPBUF; // Get data if(check==NACK) // Generate NACK signal? ACKDT = 1; // Generate NACK signal else // Case Generate ACK signal ACKDT = 0; // Generate ACK signal ACKEN = 1; // ACK enable while(!SSPIF); // Wait for ACK complete SSPIF = 0; // Clear flag return(dat); // Return data } //——————————— Function initial module i2c ————————————// void i2c_init() { TRISC3 = 1; // Ensure set SCL input mode TRISC4 = 1; // Ensure set SDA input mode SSPADD = 49; // Set SCL clock 100kHz SMP = 1; // Standard mode SSPCON = 0x08; // I2C master mode SSPEN = 1; // Enable SSP module } #endif
Listing L18-1 : i2c887.h ; library file of I2C bus interfacing for PIC16F887
62 NX-887
Experiment documentation
5. i2c_read Read 1-byte data from slave device on the I2C bus Syntax
unsigned char i2c_read(char check) Parameter check : set the acknowledge format (ACK or NACK) Return value 1-byte data from slave device
Introduction to MCP23016 I/O expander MCP23016 has more features below : • 16-bit remote bidirectional I/O port • 16 I/O pins default to 16 inputs • Fast I2C™ bus clock frequency (0 to 400 kbits/s) • Three hardware address pins allow use of up to 8 devices • High-current drive capability per I/O: ±25 mA • Open-drain interrupt output on input change • Interrupt port capture register • Internal Power-On Reset (POR) • Polarity inversion register to configure the polarity of the input port data
NX-887 Experiment documentation 63
I2C Bus Interface/ Protocol Handler of MCP23016 The MCP23016 supports the following commands:
Command Byte
Result
0x00
Access to GP0
0x01
Access to GP1
0x02
Access to OLAT0
0x03
Access to OLAT1
0x04
Access to IPOL0
0x05
Access to IPOL1
0x06
Access to IODIR0
0x07
Access to IODIR1
0x08
Access to INTCAP0 (Read-Only)
0x09
Access to INTCAP1 (Read-Only)
0x0A
Access to IOCON0
0x0B
Access to IOCON1
Address Decoder of MCP23016 is the last three LSB of the 7-bit address are user-defined. Three hardware pins (<A2:A0>) define these bits. See below. MCP23016 ADDRESS bit
7
6
5
4
3
2
1
0
0
1
0
0
A2 A1 A0 R/W
MCP23016 Data Port Registers Two registers provide access to the two GPIO ports: • GP0 (provides access to data port GP0)
bit 7
bit 0
GP0.7 GP0.6 GP0.5 GP0.4 GP0.3 GP0.2 GP0.1 GP0.0 R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
bit 7 to 0 GP0.0:GP0.7: Reflects the logic level on the pins. 1 = Logic ‘1’ 0 = Logic ‘0’
R/W - 0
64 NX-887
Experiment documentation
• GP1 (provides access to data port GP1)
bit 7
bit 0
GP1.7 GP1.6 GP1.5 GP1.4 GP1.3 GP1.2 GP1.1 GP1.0 R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
bit 7 to 0 GP1.0:GP1.7: Reflects the logic level on the pins. 1 = Logic ‘1’ 0 = Logic ‘0’ A read from this register provides status on pins of these ports. A write to these registers will modify the output latch registers (OLAT0, OLAT1) and data output.
MCP23016 Output Latch Registers Two registers provide access to the two port output latches: • OLAT0 (provides access to the output latch for port GP0)
bit 7
bit 0
OL0.7 OL0.6 OL0.5 OL0.4 OL0.3 OL0.2 OL0.1 OL0.0 R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
bit 7 to 0 OL0.0:O0.7: Reflects the logic level on the output latch. 1 = Logic ‘1’ 0 = Logic ‘0’ • OLAT1 (provides access to the output latch for port GP1)
bit 7
bit 0
OL1.7 OL1.6 OL1.5 OL1.4 OL1.3 OL1.2 OL1.1 OL1.0 R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
bit 7 to 0 OL1.0:OL1.7: Reflects the logic level on the output latch. 1 = Logic ‘1’ 0 = Logic ‘0’ A read from these registers results in a read of the latch that controls the output and not the actual port. A write to these registers updates the output latch that controls the output.
NX-887 Experiment documentation 65
MCP23016 Input Polarity Registers These registers allow the user to configure the polarity of the input port data (GP0 and GP1). If a bit in this register is set, the corresponding input port (GPn) data bit polarity will be inverted. • IPOL0 (controls the polarity of GP0)
bit 0
bit 7
IGP0.7 IGP0.6 IGP0.5 IGP0.4 IGP0.3 IGP0.2 IGP0.1 IGP0.0 R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
bit 7 to 0 IGP0.0:IGP0.7: Controls the polarity inversion for the input pins 1 = Corresponding GP0 bit is inverted 0 = Corresponding GP0 bit is not inverted • IPOL1 (controls the polarity of GP1)
bit 7
bit 0
IGP1.7 IGP1.6 IGP1.5 IGP1.4 IGP1.3 IGP1.2 IGP1.1 IGP1.0 R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
bit 7 to 0 IGP1.0:IGP1.7: Controls the polarity inversion for the input pins 1 = Corresponding GP1 bit is inverted 0 = Corresponding GP1 bit is not inverted
MCP23016 I/O Direction Regaisters Two registers control the direction of data I/O: • IODIR0 (controls GP0)
bit 7
bit 0
IOD0.7 IOD0.6 IOD0.5 IOD0.4 IOD0.3 IOD0.2 IOD0.1 IOD0.0 R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
bit 7 to 0 IOD0.0:IO0.7: Controls the direction of data I/O 1 = Input 0 = Output
R/W - 0
66 NX-887
Experiment documentation
• IODIR1 (controls GP1)
bit 7
bit 0
IOD1.7 IOD1.6 IOD1.5 IOD1.4 IOD1.3 IOD1.2 IOD1.1 IOD1.0 R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
R/W - 0
bit 7 to 0 IOD1.0:IOD1.7: Controls the direction of data I/O 1 = Input 0 = Output When a bit in these registers is set, the corresponding pin becomes an input. Otherwise, it becomes an output. At Power-on Reset, the device ports are configured as inputs.
MCP23016 Interrupt Capture Registers Two registers contain the value of the port that generated the interrupt: • INTCAP0 contains the value of GP0 at time of GP0 change interrupt
bit 7
bit 0
ICP0.7 ICP0.6 ICP0.5 ICP0.4 ICP0.3 ICP0.2 ICP0.1 ICP0.0 R-x
R-x
R-x
R-x
R-x
R-x
R-x
R-x
bit 7 to 0 ICP0.0:ICP0.7: Reflects the logic level on the GP0 pins at the time of interrupt due to pin change 1 = Logic ‘1’ 0 = Logic ‘0’ • INTCAP1 contains the value of GP1 at time of GP1 change interrupt
bit 7
bit 0
ICP1.7 ICP1.6 ICP1.5 ICP1.4 ICP1.3 ICP1.2 ICP1.1 ICP1.0 R-x
R-x
R-x
R-x
R-x
R-x
R-x
R-x
bit 7 to 0 ICP1.0:ICP1.7: Reflects the logic level on the GP1 pins at the time of interrupt due to pin change 1 = Logic ‘1’ 0 = Logic ‘0’ These registers are ‘read-only’ registers (A write to these registers is ignored).
NX-887 Experiment documentation 67
MCP23016 I/O Expander Control Register IOCON0 register controls the functionality of the MCP23016. The IARES (Interrupt Activity Resolution) bit controls the sampling frequency of the GP port pins. The higher the sampling frequency, the higher the device current requirements. This bit is LSB of IOCON0 register. All 7 MSB bits must define to “0”. If this bit is ‘0’ (default), the maximum time to detect the activity on the port is 32 ms (max.), which results in lower standby current. If this bit is ‘1’, the maximum time to detect activity on the port is 200 µsec. (max.) and results in higher standby current.
MCP23016 external component requirement MCP23016 requires a few components for operation. They are resistor and capcitor. The recommended device are 3.9k resistor and 33pF capacitor. They are connected to CLK pin as follows :
+5V 20 Vdd 15 SDA 14 SCL
IC1 MCP23016
+5V RCLK 3.9k CCLK 33pF
9 8 19
CLK
21 GP0.0 22 GP0.1 23 GP0.2 24 GP0.3 25 GP0.4 26 GP0.5 27 GP0.6 28 GP0.7
Vss Vss
User can see more information of MCP23016 with datasheet. Free download at www.microchip.com.
How to control MCP23016 Starts with sending address to MCP23016. Next is sending command and data. The data could be 1 or 2-byte. The first byte is command byte and second is written to command register. Set pin direction as input or output by writng command data 0x06 following direction data : Write “0” for choosing output and “1” for choosing input
68 NX-887
Experiment documentation
If sending only one byte, it is setting only GP0 pin function (GP0.0 to GP0.7) If sending 2-byte, it is setting all 16 i/o pin of GP0 and GP1 (GP0.0 to GP1.7) After setting direction, write the port data by : 0x02 for writing GP0 port 0x03 for writing GP1 port Reading input port do by sending 0x00 command and wait for to read each byte from MCP23016. First byte is GP0 port data and second byte is GP1 port data. The experimental C code is shown in Listing L15-2.
Experimental circuit : +5V +5V R1 10k
11 R2 510
+5V 32 RCLK 3.9k
IC1 PIC16F887 1
MCLR
+5V
SW1 RESET
CCLK 33pF
20 Vdd 9 8 19
R17 4.7k
RC3/SCL RC4/SDA
IC2 MCP23016
CLK Vss Vss
R18 4.7k
14 SCL 15 SDA
GP0.0 GP0.1 GP0.2 GP0.3 GP0.4 GP0.5 GP0.6 GP0.7 A2 A1 A0
OSC1 13 C1 22pF
21 22 23 24 25 26 27 28
R1-R8 510 LED1 LED2 LED3 LED4 LED5 LED6 LED7 LED8
18 17 16
OSC2 14 XTAL1 20MHz
C2 22pF
All 8-LED at GP0 port of MCP23016 will operate similar 8-blinking light. Writing data at GP0 are swapped between 0xAA and 0x55 every second.
NX-887 Experiment documentation 69
#include <pic.h> // Include header file for MCU #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP #include <i2c.h> // Include Library for i2c bus #define MCP23016_ID 0x40 // Constant for MCP23016 ID #define GP00x00 // Command for access to GP0 register #define OLAT0 0x02 // Command for access to OLAT0 register #define OPOL0 0x04 // Command for access to OPOL0 register #define IODIR0 0x06 // Command for access to IODIR0 register #define INTCAP0 0x08 // Command for access to INTCAP0 register #define IOCON0 0x0A // Command for access to IOCON0 register void Delay_ms(unsigned int tick) { while(tick—) // Loop counter delay time { __delay_ms(1); // Delay 1 ms } } void config_IODIR0(unsigned char dir0) { i2c_start(); // Start condition i2c_write(MCP23016_ID); // Send MCP23016 ID i2c_write(IODIR0); // Access to IODIR0 register i2c_write(dir0); // Configuration direction GP0 i2c_stop(); // Stop condition } void set_OLAT0(unsigned char dat0) { i2c_start(); // Start condition i2c_write(MCP23016_ID); // Send MCP23016 ID i2c_write(OLAT0); // Access to OLAT0 register i2c_write(dat0); // Send data to GP0 i2c_stop(); // Stop condition } void main() { unsigned char value=0; // Keep data for toggle LED i2c_init(); // Initial I2C module config_IODIR0(0x00); // Set GP0.0-GP0.7 as output set_OLAT0(0); // Clear Output LAT0 while(1) // Infinite loop { value=0xAA; // Set data output set_OLAT0(value); // Send data 0xAA to output LAT0 Delay_ms(1000); // Delay 1 sec. value=0x55; set_OLAT0(value); Delay_ms(1000);
// Set data output // Send data 0x55 to output LAT0 // Delay 1 sec.
} }
Code descritption This program starts with initial the MSSP module to I2C bus mode with i2c_init function and write direction setting command to MCP23016. Program goes to loop while{} for writing data 0xAA to OLAT0 register and 0x55 next second. The important C function of this experiment code includes 1. config_IODIR0 : Set direction to IODIR0 register 2. set_OLAT0 : Write data to OLAT0 register
Listing L15-2 : i2c_01.c ; the experimental C code for PIC16F887 interfacing with MCP23016 I/O expander via I2C bus
70 NX-887
Experiment documentation
PIC16F887 microcontroller Experiment Experiment 16 : Internal EEPROM Experiment 16.1 : Writing EEPROM during program time This experiment demonstrates the example of setting data to internal EEPROM of PIC16F887 with __EEPROM_DATA in the developed code. After that read these data to send to computer via USART port and displays on the Hyper Terminal screen.
EEPROM function of HI-TECH C compiler There are 3 functions related EEPROM mangement. All are contained in pic.h or htc.h header file. They include __EEPROM_DATA, eeprom_write and eeprom_read.
1. __EEPROM_DATA macro This macro function is writing 8-byte data to EEPROM during the program time. Do not using this macro in run time. Therefore, we tend to contain this macro in the beginning of the program to the default configuration. EEPROM address pointer is increased automatically from zero. Syntax
__EEPROM_DATA(dat0,dat1,dat2 dat3, dat4, dat5, dat6, dat7) Parameter dat0 to dat7 : 8-byte data
2. eeprom_write This function writes data to EEPROM address. It could be work in run time. Syntax
void eeprom_write(unsigned int addr,unsigned char value) Parameter addr : Target EEPROM address value : Data need to write
NX-887 Experiment documentation 71
3. eeprom_read It is reading EEPROM function. Syntax
unsigned char eeprom_read(unsigned int addr) Parameter addr : EEPROM address Return value 1-byte data from EEPROM The experimental C code is shown in Listing L16-1.
Experimental circuit : +5V +5V
+5V C5 10/50V
16
C6 10/50V 1
6 7 8
1 2 3 4 5
K1 SERIAL PORT
C4 10/50V
3
R2 510 1
5
TxD
25
8
9
RxD
26
GND
12
15
MCLR
C7 10/50V
10
6
IC1 PIC16F887
4
7
C8 10/50V
32
SW1 RESET
2
IC2 MAX232
R1 10k
11
C3 0.1/50V
RC6/TxD RC7/RxD
SK1 SERIAL DATA
OSC1 13 C1 22pF
OSC2 14
X1 20MHz
C2 22pF
72 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU #include <stdio.h> // Include Library for sprintf function #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS & DUNPROTECT); // Config. High speed clock,Disable // watchdog and Disable LVP£ __EEPROM_DATA(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07); // Initial write data to EEPROM void usart_init() { // Set buadrate 9600 bps SYNC = 0; BRGH = 1; BRG16 = 1; SPBRG = 0x08; SPBRGH = 0x02; TXEN = 1; // Enable transition CREN = 1; // Enable receive SPEN = 1; // Enable USART transition/receive } void usart_putc(unsigned char c) { while(!TRMT); // Wait transition ready TXREG = c; // Send byte } void usart_puts(unsigned char *s) { while(*s) // Loop for send string { usart_putc(*s++); // Send byte from string } } void main() { char str[6],dat; // Keep data int i; // Keep counter usart_init(); // Initial USART baudrate 9600 bps for(i=0;i<10;i++) // Loop for read data from EEPROM 10 address { dat = eeprom_read(i); // Get data from EEPROM usart_puts(“EEPROM Read Address: “); // Screen message sprintf(str,”%d “,i); // Convert address EEPROM usart_puts(str); // Display address EEPROM usart_puts(“Value: “); // Screen message sprintf(str,”%d \r\n”,dat); // Convert data EEPROM usart_puts(str); // Display data EEPROM } while(1); // Break program }
Listing L16-1 : eeprom_01.c ; the experimental C code for writing internal EEPORM of PIC16F887 in program time and read to display at the Hyper Terminal in run time via USART module
NX-887 Experiment documentation 73
The computor requirement of this experiment is one serial port. If not, must require USB to RS-232 serial port converter. UCON-232S is recommended (See details at www.inex.co.th). (1) Before testing; open the Hyper Terminal and set the properties as follows : Baudrate : 9600 bit per second Data format : 1 stop bit, no parity and 8-bit data (2) Connect the RS-232 output circuit to computer’s serial port (directly or through USB to RS-232 converter) After program running, at the Hyper Terminal screen shows message following the picture below
(3) Verify the EEPROM data reading by using Read button at PICkit 2 Programmer software.
74 NX-887
Experiment documentation
Experiment 16.2 : Read/Write EEPROM in run time This experiment demonstrates the example of writing and reading data with internal EEPROM of PIC16F887 by using eeprom_write and eeprom_read command in run time. The experimental C code is shown in Listing L16-2.
Experimental circuit : Same as the experiment 16.1. Also set the properties of Hyper terminal program and make hardware connection same the experiment 16.1. After program running, at the Hyper Terminal screen shows message
Press Key <1>,<2>,<3> for test Press Key Esc for End Try to press key 1, 2 or 3 for accessing the EEPROM address. If press ESC key, the operation is finished. At the Hyper Terminal window, press key 1. Microcontroller writes decimal data 10 to address 1 of EEPROM and reads the latest data in address 0 to 9 to displays on the Hyper Terminal screen folloiwing the picture below.
NX-887 Experiment documentation ď Źď&#x20AC; 75
Next, type 2 at the HyperTerminal PIC16F887 writes decinal data 20 to address 2 of EEPROM and reads the latest data in address 0 to 9 to displays on the Hyper Terminal screen folloiwing the picture below.
Finally, type 3 at HyperTerminal. PIC16F887 writes decinal data 30 to address 3 of EEPROM and reads the latest data in address 0 to 9 to displays on the Hyper Terminal screen folloiwing the picture below.
76 NX-887
Experiment documentation
#include <pic.h> // Include header file for MCU #include <stdio.h> // Include Library for sprintf function #define _XTAL_FREQ 20000000 // Define Frequency 20 MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP void usart_init() { // Set buadrate 9600 bps SYNC = 0; BRGH = 1; BRG16 = 1; SPBRG = 0x08; SPBRGH = 0x02; TXEN = 1; // Enable transmition CREN = 1; // Enable reciption SPEN = 1; // Enable USART transmition/receive } void usart_putc(unsigned char c) { while(!TRMT); // Wait transmition ready TXREG = c; // Send byte } void usart_puts(unsigned char *s) { while(*s) // Loop for send string { usart_putc(*s++); // Send byte from string } } unsigned char usart_getc() { while(!RCIF); // Wait data receive return(RCREG); // Return data } void main() { unsigned char str[6],key,dat; // Keep data int i; // Keep counter usart_init(); // Initial USART baudrate 9600 bps usart_puts(“Press Key <1>,<2>,<3> for test\r\n”); // Display first message usart_puts(“Press Key Esc for End \r\n”); while(1) // Infinite loop { key = usart_getc(); // Wait until data receive from keyboard if(key==27) // key Esc pressed? { break; // out from loop while(1){} } if(key==’1') // key <1> pressed? { usart_puts(“You press <1> \r\n”); // Display message key <1> pressed eeprom_write(1,10); // Write data 10 to address 1 EEPROM }
Listing L16-2 : eeprom_02.c ; the experimental C code for writing/reading internal EEPORM of PIC16F887 in run time and display data at the Hyper Terminal via USART module (continue)
NX-887 Experiment documentation 77
if(key==’2') // key <2> pressed? { usart_puts(“You press <2> \r\n”); // Display message key <2> pressed eeprom_write(2,20); // Write data 20 to address 1 EEPROM } if(key==’3') // key <3> pressed? { usart_puts(“You press <3> \r\n”); // Display message key <3> pressed eeprom_write(3,30); // Write data 30 to address 1 EEPROM } for(i=0;i<10;i++) // Loop for read data from EEPROM 10 address { dat = eeprom_read(i); // Get data from EEPROM usart_puts(“EEPROM Read Address: “); // Screen message sprintf(str,”%d “,i); // Convert address EEPROM usart_puts(str); // Display address EEPROM usart_puts(“Value: “); // Screen message sprintf(str,”%d \r\n”,dat); // Convert data EEPROM usart_puts(str); // Display data EEPROM } } usart_puts(“End...\r\n “); while(1);
// Display message for End process // Break program
}
Listing L16-2 : eeprom_02.c ; the experimental C code for writing/reading internal EEPORM of PIC16F887 in run time and display data at the Hyper Terminal via USART module (final)
78 NX-887
Experiment documentation
PIC16F887 microcontroller Experiment Experiment 17 : 1-wire interfacing with DS18B20 Digital Temperature sensor This experiment demonstrates the example about 1-wire bus interfacing of PIC16F887. The example device is DS18B20; digital temperature sensor. The library file 1wire887.h is used in this experiment. Also must include at the beginning of C code. In this experiment, PIC16F887 interfaces the DS18B20 to gets the measured temperature data to shows on the LCD module screen. Lising L17-1 is sourcecode of the 1wire887.h library file. Requires to includes at the head of program. The hardware connection definition are : 1 -wire pin as RD0 of PIC16F887 and connect 2.2k pull-up resistor at this pin. Clock frequency refer 20MHz and define at the head of program also : #define _XTAL_FREQ 20000000 The main delay function of this experiment is __delay_us or delay in microsecond.
Function description of 1wire887.h library 1. onewire_reset() Reset and start the 1-wire interfacing Syntax
char onewire_reset() Return value “0” : Slave device acknowledge “1” : No device response
2. onewire_write_byte Send 1-byte data to 1-wire device Syntax
unsigned char onewire_write_byte(unsigned char b)
Parameter b : Byte data for 1-wire device Return value Return data from the acknowledge 1-wire device
NX-887 Experiment documentation 79
//————————————————————————————————————// // Compiler: Hitech C // Library for 1-Wire bus // Hardware: RD0 ==> 1-Wire bus //————————————————————————————————————// #ifndef _1WIRE_H_ #define _1WIRE_H_ #include <pic.h> // Include header file for MCU #include <stdlib.h> #include <string.h> // Include Library for i2c bus #ifndef _XTAL_FREQ #define _XTAL_FREQ 20000000 // #endif #define ONEWIRE_TRIS TRISD0 // #define ONEWIRE_PIN RD0 // void onewire_dir_out() { ONEWIRE_TRIS = 0; // } void onewire_dir_in() { ONEWIRE_TRIS = 1; // } char onewire_reset() { char err = 0; // char GIE_tmp; // ONEWIRE_PIN = 0; // onewire_dir_out(); // __delay_us(480); // GIE_tmp = GIE; // GIE = 0; // onewire_dir_in(); // __delay_us(70); // err = ONEWIRE_PIN; // GIE = GIE_tmp; // __delay_us(480-70); // if(ONEWIRE_PIN==0) // { err = 1; // } return err; // } char onewire_write_bit(char b ) { char GIE_tmp; GIE_tmp = GIE; GIE = 0; onewire_dir_out(); __delay_us(1); if(b) { onewire_dir_in(); } __delay_us(15); if(ONEWIRE_PIN == 0) b = 0; __delay_us(60-15); onewire_dir_in(); GIE = GIE_tmp; return b; }
Define Frequency 20MHz for function __delay_us Define TRIS register for pin access Define PORT register for pin access Set direction to output port
Set direction to input port
Keep respond status Keep global interrupt status Onewire pin low Change to output port Delay 480 us Record global interrupt value Ensure disable all interrupt Change to input port Delay 70 us Read out Return global interrupt value Delay for wait check status Check respond from DS18B20 When none respond Return respond reset state
// // // // //
Keep global interrupt status Record global interrupt value Ensure disable all interrupt Change to output port Delay 1 us
// If bit is 1 set bus high // Delay 15 us // // // //
sample at end of read-timeslot Delay for write data bit state Change to input port Return global interrupt value
Listing L17-1 : 1wire887.h ; library file of 1-wire bus interfacing for PIC16F887 (continue)
80 NX-887
Experiment documentation
unsigned char onewire_write_byte(unsigned char b) { unsigned char i = 8, j; // Keep counter do { j = onewire_write_bit(b & 1); // Write data bit b >>= 1; // Shift bit 1 time if(j) // Data bit is “1”? { b |= 0x80; } } while(—i); return b; } unsigned char onewire_read_byte( void ) { return onewire_write_byte(0xFF); // read by sending 0xFF (a dontcare?) } #endif
Listing L17-1 : 1wire887.h ; library file of 1-wire bus interfacing for PIC16F887 (final) 3. onewire_read_byte Read 1-byte data from 1-wire device on the bus. Syntax
unsigned char onewire_read_byte(void) Return value Return data from the acknowledge 1-wire device.
DS18B20 introduction It is 1-wire temperature sensor device. There is 3 pins interfacing; DQ - data pin, Supply voltage pin and Ground. Conversion resolution is 12-bit. Maximum conversion time is 750 millisecond.
DS18B20
GND DQ
+Vcc
NX-887 Experiment documentation ď Źď&#x20AC; 81
DS18B20 data format is as follows : bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9
S
S
S
S
S
26
25
bit 8
bit 7
bit 6
bit 5
bit 4
bit 3
bit 2
bit 1
bit 0
24
23
22
21
20
2-1
2-2
2-3
2-4
Low-byte data
High-byte data
The example result data from DS18B20 is shown below :
Temperature (Celcius)
Data output (binary)
Data output (hexadecimal)
+125
0000 0111 1101 0000
07D0H
+85
0000 0101 0101 0000
0550H
+25.0625
0000 0001 1001 0001
0191H
+10.125
0000 0000 1010 0010
00A2H
+0.5
0000 0000 0000 1000
0008H
0
0000 0000 0000 0000
0000H
-0.5
1111 1111 1111 1000
FFF8H
-10.125
1111 1111 0101 1101
FF5EH
-25.0625
1111 1101 0110 1111
FE6FH
-55
1111 1100 1001 0000
FC90H
The memory-map of DS18B20 is shown below. It includes 2-type of memory; Scratchpad and EEPROM.
Scratchpad memory Byte 0 Low-byte temperature value Byte 1
High-byte temperature value
EEPROM memory
Byte 2
TH register or Byte 1
TH register or Byte 1
Byte 3
TL register or Byte 2
TL register or Byte 2
Byte 4
Configuration register
Configuration register
Byte 5
Reserved (FFH)
Byte 6
Reserved (0CH)
Byte 7
Reserved (10H)
Byte 8
CRC
82 NX-887
Experiment documentation
Configuration register It is used to set the temperature resolution. It has details as follows :
bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
0
R1
R0
1
1
1
1
1
Resolution select bits are R1 and R0 bit. It is set as follows :
R1
R0
Resolution
Convertion time (max)
0
0
9-bit
93.75 millisecond (tconv/8)
0
1
10-bit
187.5 millisecond (tconv/4)
1
0
11-bit
375 millisecond (tconv/2)
1
1
12-bit
750 millisecond (tconv)
The experimental C code is shown in Listing L17-2.
Experimental circuit : IC2 +5V C1 0.1F 50V
DS18B20
R1 4.7k
11
32
1 RD2
SW1 RESET
RD3
R3 2.2k
21
4
22
6
RD0
RD7 RD6 RD5 RD4
C2 22pF
E D7
30 29 28 27
OSC1 OSC2 13
DSP1 LCD 16x2 (back light option)
RS
+V Vo
IC1 PIC16F877 19
+5V
14 XTAL1 20MHz C3 22pF
14
D6 13
D5 12
D4 11
D3 10
D2
D1
D0
9
8
7
R/W 5
BLK GND 15
1
2 3 VR1 10k BRIGHTNESS
NX-887 Experiment documentation 83
#include <pic.h> // Include header file for MCU #include <lcd887.h> // Include Library for i2c bus #include <1wire887.h> // Include Library for 1-Wire bus #define _XTAL_FREQ 20000000 // Define Frequency 20MHz for function __delay_ms __CONFIG(HS & WDTDIS & LVPDIS); // Config. High speed clock,Disable watchdog and Disable LVP char temp[12]; // Keep string temp. void Delay_ms(unsigned int tick) { while(tick—) // Loop counter delay time { __delay_ms(1); // Delay 1 ms } } unsigned int read_temp(void) { unsigned char temp_buff[2]; // Keep raw temp. char err_status; // Keep respond status err_status = onewire_reset(); // Reset onewire bus if(err_status==0) // Check connection to DS1820 { onewire_write_byte(0xCC); // Skip ROM onewire_write_byte(0x44); // Start Conversion __delay_us(120); // Delay 120 us for state onewire_reset(); // Restart onewire_write_byte(0xCC); // Skip ROM onewire_write_byte(0xBE); // Read Scratch Pad temp_buff[0] = onewire_read_byte(); // Keep raw data temp_buff[1] = onewire_read_byte(); // Keep raw data } return((temp_buff[1]<<8)+temp_buff[0]); // Return raw data } char * convert_temp(unsigned int temp16) { char i=0,j=0; // Keep counter unsigned int fp = 0; // Keep value char str_fp[5]; // Keep string convert int digit_val[4]={625,1250,2500,5000}; // Decimal point if(temp16 & 0xF000) // Check sign { temp[i] = ‘-’; temp16 ^= 0x0FFF; temp16+=1; i++; } itoa(&temp[i],(temp16 & 0x0FF0)>>4,10); // Convert temp. to string strcat(temp,”.”); // Add point for(j=0;j<4;j++) // Loop for calculate decimal point
Listing L17-2 : 1wire.c ; the experimental C code for PIC16F887 to interface with DS18B20 1-wire temperature sensor and shows temperature value on LCD module (continue)
84 NX-887
Experiment documentation
{ if(temp16 & (1<<j)) { fp += digit_val[j]; } } if(fp==625) { strcat(temp,”0625"); } else if(fp==0) { strcat(temp,”0000"); } else { itoa(str_fp,fp,10); strcat(temp,str_fp); } return(temp); } void main() { unsigned int temp; lcd_init(); lcd_puts(0x80,”DS18B20 Demo...”); lcd_puts(0xC0,”Temp: “); while(1) { temp = read_temp(); lcd_puts(0xC6,” “); lcd_puts(0xC6,convert_temp(temp)); Delay_ms(2000); } }
// Decimal point is 625? // Set decimal point 4 digit // Decimal point is 0? // Set decimal point 4 digit
// Convert decimal point to string
// Return string convert
// // // // //
Keep raw temp. Initial LCD Show message at line 1 Show message at line 2 Infinite loop
// // // //
Read temp. Clear old value Update value Delay 2 sec.
Code descritption This program starts with initial LCD module with lcd_init function and program goes to loop while{} for reading temperature data from DS18B20 with read_temp function. Next, convert raw data to Temperature value in Celcius unit in string data type with convert_temp function. Delay 2 seconds before next reading. The important C function of this experiment code includes 1. read_temp : Read 2-byte of temperature raw data from DS18B20 2. convert_temp : Convert 16-bit raw data to real temperature value in Celcius in string data type for displaying on LCD modeule sceen
Listing L17-2 : 1wire.c ; the experimental C code for PIC16F887 to interface with DS18B20 1-wire temperature sensor and shows temperature value on LCD module (final)