• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

16f1827 code in asm & hi-tech c

ClydeCrashKop

Well-Known Member
Thread starter #1
Here are my first couple programs just to get it working while I read the data sheet. They both work on the 16F1827 with a 20mhz crystal. Use the other config1 line for internal clock.
Feel free to add any programs / subroutines to this thread.

Blinks 8 LEDs on PORTB in asm.
Code:
;Modified from Tutorial 1.5 - Nigel Goodwin 2002 tutorials from Electrotech online

list  p=16f1827      ; list directive to define processor
#include <p16f1827.inc> ; processor specific variable definitions
;------------------------------------------------------------------------------
;
; CONFIGURATION WORD SETUP
;    __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_ON & _IESO_OFF & _FCMEN_OFF
  __CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_ON & _IESO_OFF & _FCMEN_OFF
    __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF

cblock  0x20    ;start of general purpose registers
  count1    ;used in delay routine
  counta    ;used in delay routine
  countb    ;used in delay routine
endc
LEDPORT Equ PORTB  ;set constant LEDPORT = 'PORTB'
LEDTRIS Equ TRISB  ;set constant for TRIS register

org 0x0000  ;org sets the origin, 0x0000 for the 16F628,
    ;this is where the program starts running
; movlw 0x07
; movwf CMCON  ;turn comparators off (make it like a 16F84)
;    bsf  STATUS,  RP0 ;This doesn't work on 16F1827 use BANKSEL instead
BANKSEL TRISB
    movlw  b'00000000'  ;set PortB all outputs
    movwf  LEDTRIS
; bcf STATUS,  RP0 This doesn't work on 16F1827 use BANKSEL instead
BANKSEL PORTB
clrf LEDPORT  ;set all outputs low
Loop
movlw b'10000000'
; movlw b'11111111'
movwf LEDPORT
call Delay  ;this waits for a while!
movlw b'01000000'
movwf LEDPORT
call Delay  ;this waits for a while!
movlw b'00100000'
movwf LEDPORT
call Delay  ;this waits for a while!
movlw b'00010000'
movwf LEDPORT
call Delay  ;this waits for a while!
movlw b'00001000'
movwf LEDPORT
call Delay  ;this waits for a while!
movlw b'00000100'
movwf LEDPORT
call Delay  ;this waits for a while!
movlw b'00000010'
movwf LEDPORT
call Delay  ;this waits for a while!
movlw b'00000001'
movwf LEDPORT
call Delay  ;this waits for a while!
goto Loop  ;go back and do it again
Delay movlw d'250' ;d'250'  ;delay 250 ms (4 MHz clock)
movwf count1
d1 movlw 0xC7
movwf counta
movlw 0x01
movwf countb
Delay_0
decfsz counta, f
goto $+2
decfsz countb, f
goto Delay_0
decfsz count1 ,f
goto d1
retlw 0x00
end
Reads ADC on AN0 and outputs the high 8 bits to LEDs on PORTB in asm.

Code:
;Modified from Nigel Goodwin's tutorials from Electrotech online

list  p=16f1827      ; list directive to define processor
#include <p16f1827.inc> ; processor specific variable definitions
ERRORLEVEL 0, -302  ;suppress bank selection messages
;------------------------------------------------------------------------------
;
; CONFIGURATION WORD SETUP
;_FOSC_HS is external crystal, 20 mhz because I couldn't get internal 8 mhz working
;    __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_ON & _IESO_OFF & _FCMEN_OFF
  __CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_ON & _IESO_OFF & _FCMEN_OFF
    __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF

cblock  0x20    ;start of general purpose registers
  RESULTHI
  RESULTLO
  count1    ;used in delay routine
  counta    ;used in delay routine
  countb    ;used in delay routine
endc
org 0x0000  ;org sets the origin, 0x0000 for the 16F628,
    ;this is where the program starts running

;This code block configures the ADC
;for polling, Vdd and Vss references, Frc
;clock and AN0 input.
;
;Conversion start & polling for completion
; are included.
;
BANKSEL ADCON1 ;
; movlw  b'11110000' ;Right justify, Frc
movlw  b'01110000' ;Left justify, Frc clock
; movlw  b'00100000' ;Left justify, /32
MOVWF ADCON1 ;Vdd and Vss Vref
BANKSEL TRISB
    movlw  b'00000000'  ;set PortB all outputs
    movwf  TRISB
BANKSEL TRISA ;
BSF TRISA,0 ;Set RA0 to input
BANKSEL ANSELA ;
BSF ANSELA,0 ;Set RA0 to analog
Loop
BANKSEL ADCON0 ;
movlw  b'00000001' ;Select channel AN0
MOVWF ADCON0 ;Turn ADC On
;CALL SampleTime ;Acquisiton delay
call Delay50  ;this waits for a while!
BSF ADCON0,ADGO ;Start conversion
BTFSC ADCON0,ADGO ;Is conversion done?
GOTO $-1 ;No, test again
BANKSEL ADRESH ;
MOVF ADRESH,W ;Left justified, Read upper Byte
BANKSEL PORTB
movwf PORTB
MOVWF RESULTHI ;store in GPR space
BANKSEL ADRESL ;
MOVF ADRESL,W ;Read lower 8 bits
MOVWF RESULTLO ;Store in GPR space
goto Loop  ;go back and do it again



Delay255 movlw 0xff  ;delay 255 mS
  goto d0
Delay100 movlw d'100'  ;delay 100mS
  goto d0
Delay50  movlw d'50'  ;delay 50mS
  goto d0
Delay20  movlw d'20'  ;delay 20mS
  goto d0
Delay5  movlw 0x05  ;delay 5.000 ms (20 MHz clock)
d0  movwf count1
d1  movlw 0xE7
  movwf counta
  movlw 0x04
  movwf countb
Delay_0  decfsz counta, f
  goto $+2
  decfsz countb, f
  goto Delay_0
  decfsz count1 ,f
  goto d1
  retlw 0x00
;end of Delay routines
end
 
Last edited by a moderator:

ClydeCrashKop

Well-Known Member
Thread starter #2
If I had to read books again after being away from assembly for months, I decided to go with HI-TECH C instead. I like easy floating point math and sprintf to format output to the LCD.
I use Nigel Goodwin's tutorials in asm... http://www.winpicprog.co.uk/ for an asm library and circuits. I use his 16F628a boards for the 16F1827. (same pinout)
Now using HI-TECH C, I use Nigel's tutorials.. re-written in C by Ian Rogers. http://www.electro-tech-online.com/content/467-nigel-goodwin-s-tutorials-c.html as a starting place for C programs and subroutines.
Thank you Nigel and Ian.
Some things are changed in the 16F628a code for the enhanced 16F1827.
This is a 16 bit counter using sprintf to format output to the LCD.
This is the wiring for the LCD using Hitachi HD44780 (use on port B)
http://www.winpicprog.co.uk/pic_tutorial_lcd_board.htm

C:
// 16F1827 16 bit counter in HI-TECH C
#include <pic.h>  // pic specific identifiers
#include <stdlib.h>
#include <stdio.h>
#define _XTAL_FREQ  4000000  // Xtal speed
//  __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_ON & _IESO_OFF & _FCMEN_OFF
__CONFIG(0x01E4);// Config1 bits
//  __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF
__CONFIG(0x1CFF);    // Config2 bits
#define LCD_PORT PORTB  // constants
#define LCD_TRIS TRISB  //
#define LCD_RS   RB4
#define LCD_RW  RB6
#define LCD_E  RB7
  // Required prototypes.. each function needs to be declared
  // if called BEFORE definition.
void LCD_init(void), LCD_cmd(unsigned char ch);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);
void interrupt isr(void);
// From ADC program
void LCD_printC(const char *str), LCD_printR(char *str);
void delayMs(int x), InitADC(void);
int ReadADC(unsigned char ch);
//Original
unsigned char LCDbuffer[17];
unsigned char text1[] = {"16 bit counter."};
void main(void)  // program entry
  {
  OSCCONbits.IRCF = 0b00001101; // 4 MHz 4 bits
  ANSELB = 0;  //Set PORTB as digital I/O
  int index = 0;
  int number = 0;  // new counting variable
  LCD_TRIS = 0b00000000;  // Led port as outputs
  __delay_ms(150);  // let LCD stabilise
  LCD_init();  // Initalise screen
  LCD_goto(1,0);  // line 1.
  while(text1[index] != 0)  // while text1[index] is'nt zero
  LCD_char(text1[index++]);  // write message 1
  while(1)  // endless Loop
  {
  LCD_goto(2,1);
  sprintf(LCDbuffer,"%6u ",number);  // unsigned 6 digits
//  sprintf(LCDbuffer,"%5d ",number);  // signed 5 digits
  LCD_printR(LCDbuffer);  // use sprintf to format
  number++;
  __delay_ms(180);
  }
  }
void LCD_init()
  {
  LCD_cmd(0x20);  // 4 bit
  LCD_cmd(0x28);  // display shift
  LCD_cmd(0x6);  // character mode
  LCD_cmd(0xc);  // display on / off and cursor
  LCD_clr();  // clear display
  }
void LCD_printR(char * str)    // This passes the start of a RAM character array
  {  // by default the pointer points to data section
  while(*str != 0)  // while the character pointed to isn't 0
  LCD_char(*str++);  // print out the character, then increment
  }
void LCD_goto(char line, char column)  // combines line and lineW
  {
  unsigned char data = 0x80;  // default to 1
  if(line == 2)data = 0xc0;  // change to 2
  data += column;  // add in  column
  LCD_cmd(data);
  }
void LCD_clr()
  {
  LCD_cmd(1);  // Clr screen
  }
void LCD_cur(char on)
  {
  unsigned char cur = 0xc;  // cursor off
  if(on) cur = 0xd;  // cursor on
  LCD_cmd(cur);
  }
void LCD_cmd(unsigned char ch)
  {
  LCD_PORT = ch >> 4 & 0xf;  // write high nibble
  LCD_RS = 0;
  pulse_E();
  LCD_PORT = ch & 0xf;  // write low nibble
  LCD_RS = 0;
  pulse_E();
  __delay_ms(5);
  }
void LCD_charD(unsigned char ch)
  {
  ch+=0x30;
  LCD_char(ch);  // convert to ascii
  }
void LCD_char(unsigned char ch)
  {
  LCD_PORT = ch >> 4 & 0xf;  // High nibble
  LCD_RS = 1;
  pulse_E();
  LCD_PORT = ch & 0xf;  // low nibble
  LCD_RS = 1;
  pulse_E();
  __delay_ms(5);
  }
void pulse_E()
  {
  LCD_E = 1;
  __delay_us(1);
  LCD_E = 0;
  }
 
Last edited:

Nigel Goodwin

Super Moderator
Most Helpful Member
#3
Nice to see my tutorials moving on :)

I've been using the 16F1827 a lot recently, it's a REALLY nice device, and I've been considering adding 1827 versions to the tutorials, as I've already done various parts of them (such as the LCD routines) - but like everything else, it's a question of getting round to it.
 

ClydeCrashKop

Well-Known Member
Thread starter #4
This uses the Ultrasonic Ranging Module HC-SR04 to measure distance.
Data sheet http://elecfreaks.com/store/download/HC-SR04.pdf
Many places have them for < $5.00.
It uses the 16 bit Timer1 to measure the Echo pulse.
There are only 4 pins. +5 volts, ground, Trigger goes to RB5 and Echo goes to RA2 on the 16F1827.
There is a lot of application info online.
This is the wiring for the LCD using Hitachi HD44780
http://www.winpicprog.co.uk/pic_tutorial_lcd_board.htm

C:
// 16F1827 and Ultrasonic Ranging Module HC-SR04 to measure distance.
// LCD on port B. Trigger goes to RB5 and Echo goes to RA2.
#include <pic.h> // pic specific identifiers
#include <stdlib.h>
#include <stdio.h>
#define _XTAL_FREQ 4000000 // Xtal speed
// __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_ON & _IESO_OFF & _FCMEN_OFF
__CONFIG(0x01E4); // Config1 bits
// __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF
__CONFIG(0x1CFF); // Config2 bits
#define LCD_PORT PORTB // constants
#define LCD_TRIS TRISB //
#define LCD_RS RB4
#define LCD_RW RB6
#define LCD_E RB7
// Required prototypes.. each function needs to be declared
// if called BEFORE definition.
void LCD_init(void), LCD_cmd(unsigned char ch);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);
void LCD_printC(const char *str), LCD_printR(char *str);
unsigned char LCDbuffer[17];
unsigned char text1[] = {"Distance"};
void main(void) // program entry
{
OSCCONbits.IRCF = 0b00001101; // 4 MHz 4 bits
ANSELA = 0b11100011; //Set PORTA 2,3,4 as digital Input
ANSELB = 0; //Set PORTB as digital I/O
div_t x; // Needed for division
int index = 0;
int time = 0;
int distance = 0;
LCD_TRIS = 0b00000000; // LCD port as outputs
__delay_ms(150); // let LCD stabilise
LCD_init(); // Initalise screen
LCD_goto(1,0); // line 1.
while(text1[index] != 0) // while text1[index] is'nt zero
LCD_char(text1[index++]); // write message 1
while(1) // endless Loop
{
RB5 = 1; //Ping the sonar trigger
__delay_ms(20);
RB5 = 0; //turn off the sonar trigger
TMR1H =0;
TMR1L =0;
while(RA2==0) // wait for echo pin to go high
{}
T1CONbits.TMR1ON = 1; // turn on T1, counting until echo pin goes low
while(RA2==1) // wait for echo pin to go low
{}
T1CONbits.TMR1ON = 0; // turn off T1
time =(TMR1L+(TMR1H*256)); // all of 16 bit Timer1
LCD_goto(2,1); // line 2.
// distance=time*0.028 + 1.093 ; // Calculating the distance
distance = time / 145; // inches on mine
sprintf(LCDbuffer,"%6u",distance); // unsigned? 6 digits
LCD_printR(LCDbuffer); // use sprintf to format
LCD_goto(2,7);
LCD_char(34); // 34 is " character, 27 is '
__delay_ms(180);
}
}
 
 
void LCD_init()
{
LCD_cmd(0x20); // 4 bit
LCD_cmd(0x28); // display shift
LCD_cmd(0x6); // character mode
LCD_cmd(0xc); // display on / off and cursor
LCD_clr(); // clear display
}
void LCD_printR(char * str) // This passes the start of a RAM character array
{ // by default the pointer points to data section
while(*str != 0) // while the character pointed to isn't 0
LCD_char(*str++); // print out the character, then increment
}
 
void LCD_goto(char line, char column) // combines line and lineW
{
unsigned char data = 0x80; // default to 1
if(line == 2)data = 0xc0; // change to 2
data += column; // add in column
LCD_cmd(data);
}
void LCD_clr()
{
LCD_cmd(1); // Clr screen
}
void LCD_cur(char on)
{
unsigned char cur = 0xc; // cursor off
if(on) cur = 0xd; // cursor on
LCD_cmd(cur);
}
void LCD_cmd(unsigned char ch)
{
LCD_PORT = ch >> 4 & 0xf; // write high nibble
LCD_RS = 0;
pulse_E();
LCD_PORT = ch & 0xf; // write low nibble
LCD_RS = 0;
pulse_E();
__delay_ms(5);
}
void LCD_charD(unsigned char ch)
{
ch+=0x30;
LCD_char(ch); // convert to ascii
}
void LCD_char(unsigned char ch)
{
LCD_PORT = ch >> 4 & 0xf; // High nibble
LCD_RS = 1;
pulse_E();
LCD_PORT = ch & 0xf; // low nibble
LCD_RS = 1;
pulse_E();
__delay_ms(5);
}
void pulse_E()
{
LCD_E = 1;
__delay_us(1);
LCD_E = 0;
}
 

Attachments

Last edited:

ClydeCrashKop

Well-Known Member
Thread starter #5
This is a Dual ADC on AN0 & AN1 for the 16F1827 with LCD on Port B

C:
// Dual ADC on AN0 & AN1 for the 16F1827 with LCD on Port B
// The wiring for the LCD using Hitachi HD44780 is at
// http://www.winpicprog.co.uk/pic_tutorial_lcd_board.htm
 
#include <pic.h>                // pic specific identifiers
#include <stdio.h>
 
#define _XTAL_FREQ  4000000        // Xtal speed
//    __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_ON & _IESO_OFF & _FCMEN_OFF
__CONFIG(0x01E4);    // Config1 bits
 
//    __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF
__CONFIG(0x1CFF);      // Config2 bits
 
#define LCD_PORT PORTB            // constants
#define LCD_TRIS TRISB            //
#define LCD_RS    RB4
#define LCD_RW    RB6
#define LCD_E    RB7
 
        // Required prototypes.. each function needs to be declared
        // if called BEFORE definition.
 
void LCD_init(void), LCD_cmd(unsigned char ch);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);
void LCD_printC(const char *str), LCD_printR(char *str);
void delayMs(int x), InitADC(void);
int ReadADC(unsigned char ch);
 
    // Variables
    int number = 0;                    // new counting variable
 
unsigned char LCDbuffer[17];
 
void main(void)                        // program entry
    {
    OSCCONbits.IRCF = 0b00001101; // 4 MHz 4 bits
    ANSELB = 0;            //Set PORTB as digital I/O
    int index = 0;
    LCD_TRIS = 0b00000000;            // LCD port as outputs
    __delay_ms(150);                // let LCD stabilise
    LCD_init();                        // Initalise screen
    InitADC();                    // Initalise ADC
 
    while(1)                        // endless Loop
        {
// Reads Analog voltage on AN0 & AN1 Be sure to InitADC();
        LCD_goto(1,0);
        number = ReadADC(0);    // ADC(0) is on AN0 (RA0)
        sprintf(LCDbuffer,"CH1 %3d %04X  ",number,number);
        LCD_printR(LCDbuffer);        // use sprintf to format hex
        delayMs(10);                // as well as decimal.
// If you want the second ADC on AN1, use this.
/*        LCD_goto(2,0);
        number = ReadADC(1);    // ADC(1) is on AN1 (RA1)
        sprintf(LCDbuffer,"CH2 %3d %04X  ",number,number);
        LCD_printR(LCDbuffer);
        delayMs(10);
*/
        } //while(1)
    } //main(void)
 
 
void InitADC()
    {
    ADCON0 = 0b00000001;            // ADON
    ADCON1 = 0b11110000;            // Right justified FRC Clock                            // Set ADCON0 & 1
    }
 
int ReadADC(unsigned char ch)
    {
    int ret = 0;
    ADCON0 = 0b00000001 + (ch<<2);    // set channel to read
    delayMs(5);
    GO_nDONE =1;        // 16F1827 start conversion
      while(GO_nDONE);                    // wait for conversion
 
      ret =  (ADRESH & 0x3) << 8;        // get
      ret +=    ADRESL;                    // result
    return ret;
    }
 
 
// This may take calculated delay times. Don't use for LCD
void delayMs(int x)
    {
    while(x--)
        __delay_ms(1);
    }
 
void LCD_printC(const char * str)    // This passes the start a ROM character array
    {                                // by default the pointer points to data section
    while(*str != 0)                // while the character pointed to isn't 0
        LCD_char(*str++);            // print out the character, then increment
    }                                // the pointer down the array
 
void LCD_printR(char * str)            // This passes the start of a RAM character array
    {                                // by default the pointer points to data section
    while(*str != 0)                // while the character pointed to isn't 0
        LCD_char(*str++);            // print out the character, then increment
    }
 
void LCD_init()
    {
    LCD_cmd(0x20);                    // 4 bit
    LCD_cmd(0x28);                    // display shift
    LCD_cmd(0x6);                    // character mode
    LCD_cmd(0xc);                    // display on / off and cursor
    LCD_clr();                        // clear display
    }
 
void LCD_goto(char line, char column)        // combines line and lineW
    {
    unsigned char data = 0x80;                // default to 1
    if(line == 2)data = 0xc0;                // change to 2
    data += column;                            // add in  column
    LCD_cmd(data);
    }
 
void LCD_clr()
    {
    LCD_cmd(1);                                // Clr screen
    }
 
void LCD_cur(char on)
    {
    unsigned char cur = 0xc;                // cursor off
    if(on) cur = 0xd;                        // cursor on
    LCD_cmd(cur);
    }
 
void LCD_cmd(unsigned char ch)
    {
    LCD_PORT = ch >> 4 & 0xf;            // write high nibble
    LCD_RS = 0;
    pulse_E();
    LCD_PORT = ch & 0xf;                // write low nibble
    LCD_RS = 0;
    pulse_E();
    __delay_ms(5);
    }
 
void LCD_charD(unsigned char ch)
    {
    ch+=0x30;
    LCD_char(ch);                        // convert to ascii
    }
 
void LCD_char(unsigned char ch)
    {
    LCD_PORT = ch >> 4 & 0xf;            // High nibble
    LCD_RS = 1;
    pulse_E();
    LCD_PORT = ch & 0xf;                // low nibble
    LCD_RS = 1;
    pulse_E();
    __delay_ms(5);
    }
 
void pulse_E()
    {
    LCD_E = 1;
    __delay_us(1);
    LCD_E = 0;
    }
 

Attachments

Last edited:

Mosaic

Well-Known Member
#6
Just to add, if you're using the internal EEPROM the address for establishing assembler DE entries in these enhanced devices is no longer 0x2100. It is 0xF000!
 

Latest threads

EE World Online Articles

Loading

 
Top