Continue to Site

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.

  • 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.

PIC16F88 questions

Status
Not open for further replies.
If you have CCS C, Look in the examples folder, there is a application called EX_RTCC which reads / writes the internal clock.
 
Code

thanks WILKSEY,

Hey guys this is the code i am working on, I am trying to modify it to use a PIC16f88, I will ad the switches for military time later. Can anyone help me get this code to the point where I can compile it an test it using a pic16f88?



Is a RS232 needed ??? We have not done the lab for the RS232 yet so I am not really familiar with it.

Thanks



Code:
#if defined(__PCM__)
#include <16F877A.h>
#fuses HS,NOWDT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#elif defined(__PCH__)
#include <18F4520.h>
#fuses HS,NOWDT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#endif

#define _USE_LCD_      
#define CLOCKS_PER_SECOND  1000


#include <time.h>     
#include <rtctimer.c> 
#include <stdlib.h>
#include <input.c>      
#if defined(_USE_LCD_)
#include <lcd.c>      
#endif

void InitTime(void)
{
   struct_tm t;
   
   //tm_year is years since 1900.
   printf("\r\nYear (0-99): ");
   t.tm_year = (int16)get_int() + (int16)100;  
   
   printf("\r\nMonth (1-12): ");
   t.tm_mon = get_int() - 1;
   
   printf("\r\nDay (1-31): ");
   t.tm_mday = get_int() - 1;
   
   printf("\r\nHour (0-23): ");
   t.tm_hour = get_int();
   
   printf("\r\nMinute (0-59): ");
   t.tm_min = get_int();
   
   SetTime(&t);
   
   printf("\r\n\n");
}

void main(void)
{  
   char tString[32];
   int i = 0;
   time_t tTime = 0;
   

  #if defined(_USE_LCD_)
   lcd_init();
  #endif
  
   printf("\r\n\nex_rtctimer\r\n\n");
  
   InitTime();


  #if getenv("CLOCK")==4000000)
   setup_timer_2(T2_DIV_BY_1,250,4);
  #elif getenv("CLOCK")==20000000)
   setup_timer_2(T2_DIV_BY_4,250,5);
  #else
   #error Configure TIMER2 so it interrupts at a rate defined by CLOCKS_PER_SECOND
  #endif
   
 
   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);
   
   while(1)
   {
   
      tTime = time(NULL);
      
      ctime(&tTime, tString);
      

      printf("It is currently: %s\n\r", tString);
      
     
     #if defined(_USE_LCD_)
      lcd_gotoxy(1,1);
      i = 3; 
      while(tString[i] != '\0')
      {
         lcd_putc(tString[i]);
         i++;
      }
     #endif
      
      delay_ms(1000);
   }
}
 
Change the top part of the code to:
Code:
#include <16F88.h>
#fuses HS,NOWDT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_B5, rcv=PIN_B2)

RS232 Is needed to set the time in this particular instance, but you will eventually be able to remove this.

Does your board have a RS232 connector? If so,just plug it into your PC, fire up Hyperterminal or something similar at 9600 baud.

PS This code assumes a 20MHz clock.
 
Yeah my board has a RS232 connector. We have not gone over RS232 so I don't know which parts to change. I am not sure how to use hyper terminal, I know we have it because I was looking through the USTART lab that uses the RS232 and it mentioned it.

I tried changing the header file to PIC16f88, Do I delete the other header files?
Code:
#if defined(__PCM__)
#include <16F877A.h>
#fuses HS,NOWDT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)

#elif defined(__PCH__)
#include <18F4520.h>
#fuses HS,NOWDT,NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#endif



None of the example source codes use push buttons or switches, I believe u have to set the time and days on the from the computer. So Ive been trying to remove the parts of the code that use the RS232. Also am I going to need an external crystal??
 
Yes, you can remove the #if defined(__PCM__) and (__PCH__) defs and just have the chip you want.
You need to change the xmit and rcv pin like I did to B2 and B5 respectively, as the hardware UART is different.
Depends on what your board offers.

Hyperterminal just connects to the serial port at a specific baud rate, it is very easy to use, just set 9600, No Parity, once connected you should see some data, you could use this as an opportunity to get ahead of the game slightly and figure out the basics of the UART?

The date / time is set from the RS232, but you could adapt it fairly easily to use the LCD for output and buttons for input.

You dont need an external crystal, you will need to change the #fuses to use the internal osc though, you would have to check the header file for your chip as to the commands, normally it is INTIO for internal osc and clock pins used for i/o.

By default the OSC is 4MHz (I believe) unless you set the osc cal value to something specific.
 
printf

The source code with the header changed wouldn't compile. I brought up errors about the "printf" almost every line that had printf in it.

thanks for the help

Code:
#include <16F88.h>
#fuses HS,NOWDT,NOLVP,INTRC_IO
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_B5, rcv=PIN_B2)

#define _USE_LCD_      
#define CLOCKS_PER_SECOND  1000


#include <time.h>     
#include <rtctimer.c> 
#include <stdlib.h>
#include <input.c>      
#include <lcd.c>      


void InitTime(void)
{
   struct_tm t;
   
   //tm_year is years since 1900.
   printf("\r\nYear (0-99): ");
   t.tm_year = (int16)get_int() + (int16)100;  
   
   printf("\r\nMonth (1-12): ");
   t.tm_mon = get_int() - 1;
   
   printf("\r\nDay (1-31): ");
   t.tm_mday = get_int() - 1;
   
   printf("\r\nHour (0-23): ");
   t.tm_hour = get_int();
   
   printf("\r\nMinute (0-59): ");
   t.tm_min = get_int();
   
   SetTime(&t);
   
   printf("\r\n\n");
}

void main(void)
{  
   char tString[32];
   int i = 0;
   time_t tTime = 0;
   


   lcd_init();

  
   printf("\r\n\nex_rtctimer\r\n\n");
  
   InitTime();

    setup_oscillator(OSC_20MHZ)

 getenv("CLOCK")==4000000)
   setup_timer_2(T2_DIV_BY_1,250,4);
 getenv("CLOCK")==20000000)
   setup_timer_2(T2_DIV_BY_4,250,5);

   
 
   enable_interrupts(INT_TIMER2);
   enable_interrupts(GLOBAL);
   
   while(1)
   {
   
      tTime = time(NULL);
      
      ctime(&tTime, tString);
      

      printf("It is currently: %s\n\r", tString);
      
     
      lcd_gotoxy(1,1);
      i = 3; 
      while(tString[i] != '\0')
      {
         lcd_putc(tString[i]);
         i++;
      }
    
      
      delay_ms(1000);
   }
}
 
Last edited:
You cant set up a 20mhz internal oscillator, and you forgot some ;'s , well in fact you replaced them with )'s,

I compiled, with NO printf warnings. You did have 2 osc modes set also, so I have taken one out.

here is the part that changed:
Code:
#include <16F88.h>
#fuses NOWDT,NOLVP,INTRC_IO
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_B5, rcv=PIN_B2)

#define _USE_LCD_      
#define CLOCKS_PER_SECOND  1000


#include <time.h>     
#include <rtctimer.c> 
#include <stdlib.h>
#include <input.c>      
#include <lcd.c>      


void InitTime(void)
{
   struct_tm t;
   
   //tm_year is years since 1900.
   printf("\r\nYear (0-99): ");
   t.tm_year = (int16)get_int() + (int16)100;  
   
   printf("\r\nMonth (1-12): ");
   t.tm_mon = get_int() - 1;
   
   printf("\r\nDay (1-31): ");
   t.tm_mday = get_int() - 1;
   
   printf("\r\nHour (0-23): ");
   t.tm_hour = get_int();
   
   printf("\r\nMinute (0-59): ");
   t.tm_min = get_int();
   
   SetTime(&t);
   
   printf("\r\n\n");
}

void main(void)
{  
   char tString[32];
   int i = 0;
   time_t tTime = 0;
   


   lcd_init();

  
   printf("\r\n\nex_rtctimer\r\n\n");
  
   InitTime();


 getenv("CLOCK")==4000000;
   setup_timer_2(T2_DIV_BY_1,250,4);
 getenv("CLOCK")==20000000;
   setup_timer_2(T2_DIV_BY_4,250,5);
 
Last edited:
Compile

I am still getting tons of errors on the code.

Error 18
"H:\time.h" Line 9(10,21): File can not be opened
Not in local "H:\linkage.h"


We have not used the printf function in any of our labs so I cant really find the errors.



This I bit off more than I can chew on this project lol.

I don't know if I am allowed to ask on this board, but at this point I am willing to pay for someone to finish the code so that it can be simulated and compiled on MPLAB using CCS C code.

If anyone is interested e-mail me Danpiz23@hotmail.com,
I will pay using paypal. Thanks!
 
It sounds like you have some issues with your compiler / library directories.

What is your mapped drive H: pointing to?

I would check your CCS C Directorys
 
Post EXACTLY what you want your code to do, and we'll see if we can help you out with some of the basics.

I have used CCS C lots of times before and have never had any compiler issues like you mention, I can only assume that your directories etc are not set correctly.
 
I want the time to be displayed on the first line of the 2x16 lcd screen. On the second line of the LCD, I want to display the same time as the first line, but in military standard. I want two use 3 push button switches for inputs to set hours/minutes on the clock and I want the third switch to control the display of the military time. Unless the 3rd button is pressed I want the second line of the 2x16 LCD blank.

I think my directories were messed up, the h: drive is the one we save it too on the school computers, but the program is installed in the C; drive. I am going to try saving the program to the C; drive before it simulates/compiles.MPLAB also gave errors for expecting ")".

Thanks for the help
 
I have compiled (or tried to) the code, however it complains that the ctime function is too large to fit into the ROM, I dont think you can use the CCS C classes with that PIC, is there any other PIC chip you are allowed to use?

Wilksey
 
Yeah, I belive we are allowed to use almost any pic, every other person will be using pic16f88's though so I wanted to try to make it work with that. If its not possible then I would definalty use another PIC. I think I am going to forget about the military time and just make the LCD digital clock on the first line of the LCD with two buttons to set hr/mintures.

Thanks for the help Wilksey
 
These are the errors im getting

*** Error 18 "H:\time.h" Line 9(10,21): File can not be opened
Not in local "H:\linkage.h"
*** Error 48 "H:\time.h" Line 66(21,33): Expecting a (
*** Error 48 "H:\time.h" Line 66(24,27): Expecting a (
*** Error 48 "H:\time.h" Line 71(14,26): Expecting a (
*** Error 48 "H:\time.h" Line 72(14,26): Expecting a (


I located my Time.H file I just dont know why it wont open no matter what folder I have it in.
 
How about this

Hey Wilksey,

I was trying to use this code, i got a few errors while compiling.
These are the errors
Code:
Executing: "C:\Program Files\Microchip\Third Party\PICC\Ccsc.exe" +FM "Lab1.c" +DF +LN +T +A +M +Z +Y=9 +EA
*** Error 18 "Lab1.c" Line 3(10,17): File can not be opened
    Not in local "H:\bit.h"
*** Error 18 "Lab1.c" Line 4(10,17): File can not be opened
    Not in local "H:\I2C.h"
*** Error 128 "Lab1.c" Line 12(1,4): A #DEVICE required before this line
      3 Errors,  0 Warnings.
Halting build on first failure as requested.
BUILD FAILED: Thu Apr 29 17:35:40 2010


Code:
#include "bit.h"
#include "I2C.h"

//////////////////////////////////////////////////////////////////////
// macros / defines
#define UP    1
#define DOWN -1

//////////////////////////////////////////////////////////////////////
typedef unsigned short Byte;
typedef unsigned short UINT8;

//////////////////////////////////////////////////////////////////////
// File scope variables
static Byte ds1307_started = 0;

//////////////////////////////////////////////////////////////////////
// Read the keys
unsigned short read_ANA_keys(void) {
unsigned int val;
   val = Adc_Read(0);

   // Decode the analogue
   if (val>800 && val<860) {val=1;}
   else if (val>490 && val<530) {val=2;}
   else if (val>300 && val<350) {val=3;}
   else if (val<300) {val=4;}
   else {val=0;}

   return val;
}

//////////////////////////////////////////////////////////////////////
// globals for interrupt.
//
//////////////////////////////////////////////////////////////////////
void init(void) {
 int i,ack,c;

   OSCCON  = 0x70; // b6..4 = 110 = 4MHz    111=8MHz

   ANSEL = 0x00;   // RA0 enabled as needed in program.

   // Timer 1 on
   T1CON = (1<<TMR1ON);
}

//////////////////////////////////////////////////////////////////////
void init_ports(void) {

   PORTA = 0;
   TRISA = 0x00;     // 0=o/p  - sets analogue pins to digital output.
                     // AN0 set to input as needed.

   PORTB = 0;

   TRISB = 0x01;  // 0=o/p // Receive on RB0.
}

//////////////////////////////////////////////////////////////////////
// RA5 can only be input on 16F88 so move bit 5 to 6, 6 to 7.
//
// ret table is for straight through
// PORT 0 1 2 3 4 5 6 7 to a b c d e f g dp
// So map to new outputs:
// 0 a, 1 b, 2 c, 3 d, 4 e, 6 f, 7 g - loosing dp
// i.e. keep 1st 5 and move bits 5,6 to 6,7

unsigned short int2seg(unsigned short digit) {
unsigned short r;
unsigned short ret[10] = { 0x3F, 0x06, 0x5B, 0x4F, 0x66,
                           0x6D, 0x7D, 0x07, 0x7F, 0x6F };

   if (digit<0 || digit>9) {
      r = 0x7f;
   } else {
      r =(  ret[digit] & 0x1f ) | \
         ( (ret[digit] & 0x60)<< 1);
   }

   return r;
}

//////////////////////////////////////////////////////////////////////
void write_DS1307(unsigned short address, unsigned short data) {
short i;

   _I2C_Start();
   _I2C_Wr(0xd0);
   _I2C_Wr(address);
   _I2C_Wr(data);
   _I2C_Stop();

   _I2C_Start();

   // Get an ACK from the slave but give up after 3 goes don't hang waiting.
   for(i=0;i<3;i++) {
      if (_I2C_Wr(0xd0)==1) {  // Check for NACK
         _I2C_start();
      } else break;            // found ACK
   }
   _I2C_Stop();
}

//////////////////////////////////////////////////////////////////////
unsigned short read_ds1307(unsigned short address) {
unsigned short data;

   _I2C_Start();
   _I2C_Wr(0xd0);
   _I2C_Wr(address);
   _I2C_Start();
   _I2C_Wr(0xd1);           // b0 is read
   data=_I2C_Rd(0);         // Read with NACK.
   _I2C_stop();
   return(data);
}


//////////////////////////////////////////////////////////////////////
void start_ds1307() {
Byte sec;

   if (ds1307_started) return;

   sec = read_ds1307(0) & ~0x80; // CH = 0 - start.
   write_DS1307(0,sec);
   ds1307_started = 1;
}

//////////////////////////////////////////////////////////////////////
void stop_ds1307() {
   Byte sec;
   sec = read_ds1307(0) | 0x80; // CH = 1 - stop.
   write_DS1307(0,sec);

   ds1307_started = 0;
}

//////////////////////////////////////////////////////////////////////
// Register update only happens if year data is not present.
// Have to change this next centuary!
//
void init_ds1307(void) {

   // Check if initialisation is needed by checking a ram location
   // use the year value : RAM location 3F is used to hold the year data

   if (read_ds1307(0x3f)==0x20) {return;} // initialised so return

   start_ds1307(); // Start the oscillator

   // Set to 24H mode
   write_ds1307(2,read_ds1307(2) & ~(1<<6) ); // reset bit 6 for 24 hour mode.

   // Set the time
   write_ds1307(0,0x59 & 0x7F); // bit 7 - oscailltor halt (if=1).  : secs  0-59
   write_ds1307(1,0x59);  //                                        : mins  0-59
   write_ds1307(2,0x24 & ~(1<<6) ); // reset bit 6 for 24 hour mode.:0-23,1-12 hour
   write_ds1307(3,0x07);  // week day day 0-7                       : day   1-7
   write_ds1307(4,0x31);  // (exceptions Feb,Apr,Jun,Sep,Nov 1-30)  : date  1-31
   write_ds1307(5,0x12);  //                                        : month 1-12
   write_ds1307(6,0x99);  //                                        : year  0-99
   // Write high digit of year into RAM easier code
   // and gives initialisation check.
   write_ds1307(0x3f,0x20);    //                                   : year  20
}


//////////////////////////////////////////////////////////////////////
// Edit the DS1307 at address Addr
// add or subtract dir e.g. -1, +1, -10, +10.
//
// Stores the special case bits for
//   CH and 12/24hour
// restoring them at the end.
//
void edit_DS1307(Byte Addr, Byte dir) {
UINT8 store=0;
UINT8 lim,low_lim;
int data=0;

   data = read_ds1307(Addr); // Get the data.

   switch (Addr) { // Control special case bits
      case 0 : store = data & 0x80;  data &=0x7f; break; // CH Clock Halt.
      case 2 : store = data &(1<<6); data &=0x3f; break; // 12/24 Hour
   }

   data = Bcd2Dec(data);    // Convert

   // Limits
   low_lim=0;
   switch (Addr) {
   case 0 :
   case 1 : lim=59; break;
   case 2 : lim=23; break;
   case 3 : lim=7;  low_lim=1; break;
   case 4 : lim=31; low_lim=1; break;
   case 5 : lim=12; low_lim=1; break;
   case 6 : lim=99; break;
   }

   data += dir;

   // Process limits
   if (data<low_lim) data=lim;
   if (data>lim)     data=low_lim;

   // finish up and restore ctrl bits
   write_DS1307( Addr, Dec2Bcd(data) | store );
}

//////////////////////////////////////////////////////////////////////
// clock_display
//
// Arguments
//    bcd1 - displayed on left of segment (2 digits)
//    bcd2 - displayed on right of segment (2 digits)
//    blankLR -1 for no digit, 0-left, 1-right // selectively blank digits
//
// Each call to this routine displays a single digit
// this lets the caller do more work
// as delays between calls to this routine
// are controled from the caller.
//
// blankLRidx =
void clock_display(UINT8 ad1, UINT8 ad2, Byte blankLRidx) {
static UINT8 digit=0;
UINT8 pin, bcd;
char op[4];
int num;

   if (++digit==5) {digit=1;}

   if (digit<=2) { // Get the data
      bcd = read_ds1307(ad1);  // hours only  appear in left  digit set.
      if (ad1==2) bcd &= ~(1<<6);
      ByteToStr(Bcd2Dec(bcd),op);      // Left
   } else {
      bcd = read_ds1307(ad2);
      if (ad2==0) bcd &=0x7f; // seconds only appear in right digit set.
      ByteToStr(Bcd2Dec(bcd),op);      // Right
   }

   switch (digit) { // Choose the segment drives and display digit.
      case 1 : pin=5; num=op[1]; break;
      case 2 : pin=2; num=op[2]; break;
      case 3 : pin=6; num=op[1]; break;
      case 4 : pin=7; num=op[2]; break;
   }

   num = num - '0'; // convert to number

   if ( (digit<=2 && blankLRidx==0) ||
        (digit>=3 && blankLRidx==1)) {
      PORTA=0;             // Blank
   } else {
      PORTA=int2seg(num);  // No blank
   }

   setBit(PORTB,pin);
   delay_ms(1);
   resBit(PORTB,pin);
   PORTA=0;

   PORTB=0;
}   // clock display

//////////////////////////////////////////////////////////////////////
void main() {

unsigned short mode=0;      // Current display mode.
short edit=-1;              // Change digit index or -1 - normal clock mode.
unsigned short key=0;       // Current key press.
unsigned short last_key=0;  // Detect key press changes.
unsigned short idx[2];      // Easier readability for code = DS1307 addresses.
unsigned short flash=0;     // Control to flash a selected digit.
unsigned short blankIdx=0;  // Flash digit control.
unsigned short hrs;         // Temporary store.

   init_ports();
   init();

   _I2C_Init(100000);

   init_ds1307();

   while(1) {

      TRISB = (1<<1) | (1<<4);   // Ensure SDA and SLC are inputs

      TRISA = 0x01; // AN0 input to read the keys
      ANSEL = 0x01; // Activate analogue input AN0
      delay_us(100);
      key = read_ANA_keys();

      TRISA &= ~0x01; // AN0 input set as o/p to control the 7segment display.
      ANSEL = 0x00;   // Digital I/O

      if (key!=last_key) {
         switch (key) {

         case 1 : // MODE i.e. select data to show on 7seg.
            mode++;
            if (mode>3) {mode=0;}

            edit=-1;

            // Changing mode so start the clock - only does it if stopped
            start_ds1307();

            break;

         case 2 : // Select left or right digits to change
            // -1 - no digits selected, 0- left 1- right
            if (++edit>1) { // Finished editing - index is > 1
                edit=-1;
                start_ds1307(); // Leaving edit mode so start the clock

            } else if (mode==0 && edit!=-1) {
               // clock halt if editing seconds i.e. edit active in mode 0
               stop_ds1307();
            }
            break;

         case 3 : // UP
            if (edit!=-1) edit_DS1307(idx[edit],UP);
            break;

         case 4 : // DOWN
            if (edit!=-1) edit_DS1307(idx[edit],DOWN);
            break;

         }
         last_key = key; // react only to key changes
      } // key changed.

      // Select data to display.
      switch (mode) {
         case 0 : idx[0] = 1;    idx[1] = 0; break; // Minutes, Secs.
         case 1 : idx[0] = 2;    idx[1] = 1; break; // Hours, Minutes.
         case 2 : idx[0] = 4;    idx[1] = 5; break; // Date, Month.
         case 3 : idx[0] = 0x3f; idx[1] = 6; break; // YEAR 8-ram address.
      }

      if (++flash>60) flash=0; // Cycle flash value.

      // Do the displaying / flash a digit if edit !=0
      if (flash>30)
         blankIdx = edit;   // select digit to blank.
      else
         blankIdx = -1;     // no digit is blanked.

      clock_display(idx[0],idx[1], blankIdx);

   } // while(1)
}
 
I have removed the rtc time routines and started looking at alternatives, I have the time running on the LCD correctly, just need to implement the hours and minutes button.
Uses a lot less space than the supplied CCS C example, and it's easier to understand (in my opinion).

I am away this weekend (it is a holiday weekend in the UK) and I am in the process of changing internet providers so I can only really answer while i'm at work, so I will try and get something ready for Tuesday for you.

Wilksey
 
This should help.

I have attached a ZIP file which contains the code, compiled code, CCS C Project, and the Proteus 7 Design, You may need to tweak the pins for your board hardware, but the code is there and working.

I have added a "function" key which toggles, so you can use this to display your military time etc if needed.

Hope this helps.

Regards

Wilksey
 

Attachments

  • RTC.zip
    61.6 KB · Views: 172
Thanks Alot Wilksey, I am going to try the code as soon as I get to lab. If I am using MPlad do I need to load all the zipped or can I just use the Test.c file??
 
Status
Not open for further replies.

Latest threads

Back
Top