Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[SOLVED] PIC16F877 RTC Creating a setup mode.

Status
Not open for further replies.

WStevens_sa

Member level 2
Joined
Jan 5, 2011
Messages
47
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Location
South Africa
Activity points
1,695
Hi all

Please can you point me in the correct direction. I have a PIC16f877 programmable RTC timer with 2 x 16 LCD displayed with eg "MON 14:56". I have figured out everything I need so far and have written the code for it and tested with simulator. It all works well.

I want to create a startup / program mode. When the timer is initially started up for the first time nothing will be set. For example the day and time will be displayed as "--- --:--" and the 8 configurable timers will be disabled.

Long story short. If I push the mode button it will take me through the steps of programming the timer.

  1. Press mode button for 2 seconds and it enters setup mode.
  2. Cursor moves to the LCD position where the day value is displayed.
  3. By using up down button set the day. eg (mon, tues, etc)
  4. Press mode button again it takes you to the hours. use up/down button to set hours
  5. And this will occur with the setting up of the timers too.
  6. If the setup mode is idle for more then 3 seconds it must go back to normal mode

I have know idea where to start. I would appreciate any help, links or documentation just to get an idea where to start.
 

i think in frist time when u read from RTC u read the intial values like SUN 00:00

---------- Post added at 20:40 ---------- Previous post was at 20:39 ----------

the hour is 0 and min is 0 not 00:00 but 0:0

---------- Post added at 20:43 ---------- Previous post was at 20:40 ----------

frist u ener for brust mode for RTC then u value entered from user is saved in var.
then send all the varaible(Hr-min-day-month.....) to RTC.
or u send to each register in separatly to adjust it.
 

Hi WStevens_sa,

It looks to me like you have a pretty good idea of what you want to accomplish, and that's the first (and probably hardest) step in every project. So make sure you have a perfectly clear picture of what your system should do before stepping into how to do it.
Then separate all the things to do into logically unrelated “tasks” and try to split those into smaller functional units.
For instance, taking your plan above as an example, accepting input from a key is unrelated and should be a totally independent task from keeping the current time or displaying some data.
But then, accepting key input involves reading a logic level on a port pin, filtering (in HW) and/or debouncing (in SW), figuring a short key-press from a long one, assigning a key codes (maybe allow even multiple key pressed at once) etc.
Further down the hierarchy, debouncing can be done by reading the key input one more time after about 30ms (max 50ms for a good responsiveness). And so on.
When you have broken down all the things to do, like that, in tasks and functions, you can start deciding how to best use the uC’s resources (now that you already chose one), such as serving interrupt requests as opposed to polling, or using dedicated peripherals (timers, communication etc.) instead of software delays and bit-banging.
Write your tasks to work independently or with very little interaction with each other (via shared flags/semaphores for synchronization, or to signal that data is available).
Keep ISRs simple and short (as in “read, store, signal data available, return”) and do the bulk of the work in the main loop (where you’ll run all of your other tasks in an infinite loop).
The tasks will check the flags for “data availability”, or whatever, but will probably do nothing most of the time, wating for their cue.
You can treat all tasks this way, including those that need to run periodically, at specific time intervals. Don’t do them in the ISR, instead, let the ISR count the time interval and signal some flag (basically a bit or a boolean variable) when the task should run. The task running in the in the main, infinite loop, checks the flag and runs if it finds it true then sets it to false.

Your main loop could look like this:

Code:
void main(void)
{
   clock_Init();	// init system clock etc.
   nvram_Init();	// read stored system parameters
   keyb_Init();		// init key input
   time_Init();
   state_Init();	// state machine init
   /* init other module and variables */
   while(1)
   {// this is the main loop
      alarm_task();	// check if any timer elapsed
      keyb_task();	// check and process key press
      state_task();	// evaluate and advance state machine
      disp_task();	// update display
      /* other tasks */
   }
}
…I actually run out of time myself now, but raise the questions as they pop-up and well sort them somehow…

Arthur
 
Last edited:
Hi Arthur

Here is what I have done so far. I think im on the correct path. My coding can be a bit better in the sense of not repeating functions to do tasks. I only have a few things I am struggling with. For example the " if (Button(&PORTC, 2, 1, 1))" where I am not sure how to get one button to do 2 functions. For example If I push a button it does one function. if I push the same button for 3 seconds it must do another function. I am also using multiple while do statements, which I think is also not a good thing for memory resources.

You also talk about flags. I am not sure what you mean. Do you mean a variable for example " int timer_set = 0;" So timer_set can be either 0 or 1. Is this what you mean with flags. The other thing that concerns me is that I am currently using 52.8 % of the ram and only have 47.2% left. This is obviousley all the variables declared I think. Rom is only 24.8 % used and 75.2 available. I dont want to bog down the MCU with calculations. I still need to add error checking on external devices that attach. So what would you recommend is the maximum preferred memory to use before it bogs down the MCU.

CLOCK.C

//EXTERNAL SOURCES
extern void tmr_check(int a, int b, int c);
extern void con_set();

// VARIABLES FOR LCD CONNECTIONS
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;
sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;


// INTERRUPT VARIABLES
int int_count = 0 ;
int dd, hh, mm, ss;
int bmin = 0;

char* wdays[7] = {"MON","TUE","WED","THU","FRI","SAT","SUN"};

//DAILY TIMER VARIABLES
int tm_set[8] = {1,1,1,1,1,1,1,0}; // Is timer enabled
int tm_on[8] = {930,2460,3480,5100,6480,7680,9000,0}; // time on in int
int tm_off[8] = {990,2520,3540,5160,6540,7740,9060,0}; // time off in int
int tm_act[8] = {0,0,0,0,0,0,0,0};
// timer is currently on

// INTERRUPT RTC
void interrupt(void) {

if(T0IF_bit == 1){ // Check for interrupt flag

T0IF_bit=0; //Reset flag
int_count++ ;
if(int_count > 15625){ // 1 sec 16 Mhz crystal = 16000000 / 4 / 256 =15625
int_count = 0 ;
ss++ ;
if(ss == 60){
ss = 0 ;
mm++ ;
bmin++;
if (bmin == 10080){
bmin = 0;
}
if(mm == 60){
mm = 0 ;
hh++ ;

if(hh == 24){
hh = 0 ;
dd++;

if (dd == 7){
dd = 0;
}
}
}
}
}
}
}

void main(){
//LCD
Lcd_Init(); // Initialize LCD
Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off

Lcd_out(1,7,":");
Lcd_out(1,10,":");
//lcd_out(1,12,"55°c");

//TMR0
OPTION_REG = 8;
GIE_bit = 1; //Enable Global Interrupt
T0IF_bit = 0; //Clear interrupt flag
T0IE_bit = 1; //Enable TMR0 interrupt
PEIE_bit = 1; //Peripheral Interrupt Enable bit

//PUSH BUTTON SETTINGs
ADCON1 = 0;
TRISA = 1; //PortA all input
PORTA = 0;
TRISC = 15; // Configure PORTC as output Works on binary count 101 sets port RC0 and RC2
PORTC = 0; // Initial PORTC value

while(1){


//SECONDS
Lcd_Chr(1,12,48+(ss % 10)); // seconds counter LSB
Lcd_Chr(1,11,48+((ss /10) % 10)); //Seconds counter MSB

//MINUTES
Lcd_Chr(1,9,48+(mm % 10)); // minutes counter LSB
Lcd_Chr(1,8,48+((mm /10) % 10)); //minutes counter MSB

//HOURS
Lcd_Chr(1,6,48+(hh % 10)); // hours counter LSB
Lcd_Chr(1,5,48+((hh /10) % 10)); // hours counter MSB

//DAYS
Lcd_out(1,1,wdays[dd]); // days of the week

//CHECK FOR ACTIVE TIMERS
tmr_check(dd,hh,mm); // int cday, int chour,int cmin

//PUSHBUTTON ACCESS SETUP MODE
if (Button(&PORTC, 0, 1, 1)) {//SETUP MODE
Lcd_Cmd(_LCD_CLEAR);
con_set();
}
}
}

TIMERCHECK.C

int tm_val;
extern tm_set[8];extern tm_on[8];extern tm_off[8];
extern tm_act[8];extern char* wdays[7];

//SET TMR ACTIVE
void tm_ico(int dd, int val, char* day, char* msg){
tm_act[dd] = val; Lcd_out(2,1,day); Lcd_out(2,5,msg);
}

//CHECK TIMER STATUS
void tmr_check(int dd, int hh, int mm ){
//CALC BIG MINUTES CURRENT DATE & TIME
tm_val = ((dd*24)*60) + (hh * 60) + (mm);

if (tm_set[8]==1) //IF GROUP TIMER ACTIVE IGNORE ALL OTHER TIMERS
{
/* this is where you default to group timer */
}
else
{
if (tm_set[dd]== 1 ) //IS TIMER ENABLED
{
if (tm_act[dd] == 0) // if timer is not active then check on tm_on
{
if (tm_on[dd] == tm_val){tm_ico(dd,1,wdays[dd],"TMR ON ");} //if time_on >= current day val turn timer on
}
else
{
if (tm_off[dd] == tm_val){ tm_ico(dd,0,wdays[dd],"TMR OFF");} //if time_off >= current day val turn timer off

}
}
}
}


SETUP MODE.C

int mode;
extern dd, hh, mm, ss;
extern char* wdays[7];
int dint=0;
int txt;


void set_min(void){
//lcd_out(1,8,"test");
while(1) {

if (Button(&PORTC, 1, 1, 1)) {
Delay_ms(300);
mm++;
if(mm == 59) {mm = 0;}
}
if (Button(&PORTC, 2, 1, 1)) {
if(mm == 0) {mm = 59;}
Delay_ms(300);
mm--;
}
if (Button(&PORTC, 3, 1, 1)) { // ENTER
//Lcd_Cmd(_LCD_CLEAR);

}


Lcd_Chr(1,9,48+(mm % 10)); // minutes counter LSB
Lcd_Chr(1,8,48+((mm /10) % 10)); //minutes counter MSB


}
}

void set_hour(void){
lcd_out(1,5,"00");
while(1) {

if (Button(&PORTC, 1, 1, 1)) {
Delay_ms(300);
hh++;
if(hh == 24) {hh = 0;}
}
if (Button(&PORTC, 2, 1, 1)) {
if(hh == 0) {hh = 24;}
Delay_ms(300);
hh--;
}
if (Button(&PORTC, 3, 1, 1)) { // ENTER
set_min();
}
Lcd_Chr(1,6,48+(hh % 10)); // hours counter LSB
Lcd_Chr(1,5,48+((hh /10) % 10)); // hours counter MSB
}
}

void set_day(){

while(1){

if (Button(&PORTC, 1, 1, 1)) {
Delay_ms(300); dd++; if(dd == 7) {dd = 0;}
}
if (Button(&PORTC, 2, 1, 1)) {
if(dd == 0) {dd = 7;}Delay_ms(300);dd--;
}
if (Button(&PORTC, 3, 1, 1)) { // ENTER

set_hour();
}
lcd_out(1,1,wdays[dd]);
}

}

void con_set(){

while(1){

switch (mode) {
case 0: lcd_out(1,1,"CLOCK"); break;
case 1: lcd_out(1,1,"TIMERS"); break;
case 2: lcd_out(1,1,"TEMP"); break; }

if (Button(&PORTC, 1, 1, 1)) { //UP
mode++;
Delay_ms(300);
Lcd_Cmd(_LCD_CLEAR);
if (mode == 3) {mode=0;}
}
if (Button(&PORTC, 2, 1, 1)) { //DOWN
if (mode == 0) {mode=3;}
mode--;
Delay_ms(300);
Lcd_Cmd(_LCD_CLEAR);

}
if (Button(&PORTC, 3, 1, 1)) { // ENTER
Lcd_Cmd(_LCD_CLEAR);
Delay_ms(300);
set_day();

}
}
}
 

Hi!
WStevens_sa

I only have a few things I am struggling with. For example the " if (Button(&PORTC, 2, 1, 1))" where I am not sure how to get one button to do 2 functions. For example If I push a button it does one function. if I push the same button for 3 seconds it must do another function.

unsigned int x=0;
void main(){
while(Button(&PORTC,2,1,0)){
x++;
Delay_ms(1000); //Increment value of x every second.........
}
if(x<3){/*your code*/} //If less than 3 seconds
else if(x>=3){/*your code*/} //After 3 seconds
x=0;
}
 
Last edited:
WStevens_sa,
You might get away with your little project, but I don't think you're on the correct path...
You haven't implemented anything of what I was talking about in my previous post and I have more comments than time to write it so I will keep it short and only answer to your questions.

In my previous post, I briefly suggested how I would use the key input.
First of all, you have to decide how many keys you'll need. The way you explained it, you only planned a “mode” key and 2 adjustments (“up”, “down”) keys. The less keys you’ll have, the more difficult the user experience and coding will be. If you have the possibility, assign keys for “day”, “hour”, “minute”, “alarm”, “+” and “-“.

The best way to detect a key press is with interrupts. If you can assign an interrupt requests on a port on both rising and falling edges, put your keys there. To detect “key down”, initialize the input pin to request interrupts on the falling edge (providing that the key connects the port pin to ground when pressed). In the ISR (Interrupt Service Routine) of a particular key, setup a timer to trigger an interrupt in 30ms. When the timer elapses, check the key again. If it’s still down then you consider that particular key debounced. Now setup the port to request interrupts on the rising edge, while setting up the timer to elapse after 3 seconds (if that’s your desired “long key press”). If the IRQ of the port pin is triggered before the timer’s, you got a “short press”. If it occurs after the timer, you got a “long press”.
I know it all sounds a bit complicated, but it isn’t really and, believe me, I’ve done this in all possible ways and this is the most robust way.

Another way is to poll the key-pins in the main loop and count the number of times they where found down. You will reset the counter whenever the key was found up. You still have to do the polling at specific time intervals (50ms, at most) to be able to differentiate short and long presses.

If you do it like Denshil suggested, your display (and everything else) will freeze as long as you keep the key pressed and you should absolutely avoid that...

When I say “flags”, I mean bits or variables that signal something. In that particular case, I meant a Boolean variable that can be “true” or “false” (that can be emulated with a char taking “0” or “anything else”). The whole point being that a “flag” should be easier/faster to check than accessing the actual data.

It’s probably too early to worry about memory allocation. Using a lot of memory won’t make your chip slower (it’s not Windows doing swaps on disk). Use it all, that’s why you have it! If you run out of it, you can start optimizing. Of course, you could be quite a bit more organized in your coding and that will surely help memory usage as well...

Arthur
 
Last edited:
Hi Arthur

My apologies if I have confused you. I actually wrote the code above before I posted this thread as I have been trying out different code to do different things to learn all the basics before I get stuck in with writing proper structured code. I will be re-programming the code in the structure as you explained in your first post but I am now first laying out a proper plan. As to the programming I am actually a Microsoft Developer so code complexity and optimisation is something I am familiar with. I am only struggling because I have never programmed in C for MCU's. I usually use C#.net, vb.net, javascripting, html, xml, flash and other languages. I will be trying out all your methods and will keep you updated as to my project. I appreciate all the help I get from everybody as this helps me learn

Hi Denshil

I appreciate all your responses. You have helped me a lot with all my posts. Thanks again.

I will keep you all informed with code snippets.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top