Jump to content

ra68gi

EstablishedMember
  • Content Count

    229
  • Joined

  • Last visited

Everything posted by ra68gi

  1. Trossin, I live in India which is seeing tremendous industrial & economic growth and with that comes a huge energy demand. Unable to meet with the peak demand many a times the frequency dips far below the normal( 50 Hz) in our place. Line frequency as clock is out of question. But your second option looks great. I should check out if such a clock is available here. Regards Raghunathan.
  2. You still have a problem. You have it fixed in your head that the number TMR0 needs to count from is 250. This is incorrect. The correct number is 249 because this number will cause TMR0 to go through 250 count states and then set the TMR0IF flag. Using tmr0+=8; to set the period of TMR0 will cause it to use 251 count states. Think of the TMR0 as if it's an index of an array in C. If the array is 250 elements then the index of the first element is 0 and the last is 249. <{POST_SNAPBACK}> Hi ca001, i think, you have missed a few lines of my explaination. We all know that tmr0 will show values from 0-255 only. If you count from 0-255 you will get only 255 counts and not 256. Only when the counter counts back from 255-0, would we count 256. Check it out. A small Quick check. Let's have a counter upto 5. 0-1..........1 count 1-2...........2 2-3............3 3-4.............4 4-5...............5 now 5-0.................6 So if you count upto 249, you make 249 counts or ticks o.k. But you can not make tmr0 register to count upto 249 and then jump to 0. Because tmr0 will generate interrupt only when the counter changes from 255 to 0. So what we do, we make it to start counting from 6. AS you say 255-6=249. So you have your magical no.249. And now when the counter jumps to 0 from 255, eventually you have counted 250. Again we know that the counter sleeps for 2 ticks upon writing 6 to tmr0. but that does not mean that the real time isn't changing. This elapsed 2 clock cycles of real time is also added to 6 and so becomes 8. I hope this explaination satisfies you. Regards Raghunathan.
  3. Yes, after all this dicussion i have a better picture. I was wrong in loading tmr0+=2; I took this wrong decision based on the tmr0 register value on the simulator. As Dave says, if the simulator & hardware behaves in a similar way then i sould load the value as tmr0+=8; and not be botherd about the value shown on the simulator. tmr0+=8;( 6 clock cycles to get 250 count & 2 more for delay in write operation). Finally as Trossin says, the proof of the pudding is in its eating. Let me load this value and run my clock for a day and compare it with some other standard clock(do we have one?). cac001, you can see that i am setting the tmr0 as soon as i enter the ISR. Thats the first c instruction. Instead of saying "you need to set the count register to count 250 instruction " you could say you need to count 250 clock cycle. Again tmr0 is in the habbit of counting upto 256 ( to be precise it counts upto 255 & when it rolls over to 0(ie.256 count) it sets the interrupt) before it sets the interrupt flag. So we need to make it count only 250 before it sets the interrupt flag and this we do by making it not count 6 clock cycle. In an ideal condition where upon entering the ISR if your tmr0 shows 0 we simply we would like to start tmr0 from counter value 6. which we would write in c as tmr0=6;. From the data sheet we know we need to add 2 more since the micro halts for 2 clock cycle before it registers this value so we should write tmr0=8; But we do not have an ideal world and by the time we enter the ISR the tmr0 would have clocked a few ticks (to save the various registers). Let us say its 20 clock cycles, so tmr0 will show 20.But you can be sure its defnitely not going to take more than 50 clock cycle to save all this file. This being the case we simply give tmr0 an addition advantage or handicap of 8 clock cycle for it to generate the next interrupt. For this we simply add 8 to the alredy existing counter value. So we write in C as tmr0+=8;. Irrespective of what the tmr0 counter is upon entering the ISR we simply add 8 to it. Time taken for save operation can vary but that will not effect our accuracy, because we simply add 8 to get tmr0 to count 250. Next the code for incrementing and setting the flag of the seconds minutes and hours is done. We sould make sure this whole process does not take more than 150 clock cycles(thats a lot of time and we can confortably finish the whole thing in less than 25 clock cycles). Finally we clear the interrupt Flag so that we are ready to receive the next interrupt. In the main program we just check the flag and spend most of the time firing the 7-segment displays. Thats all to it. Finally as Trossin says the accuracy & effect of drift in the crystal will decide how accurate your clock will be.
  4. There is no compenastion for any code execution delays. You have todo that in your code (maybe you even need to use inline assembler to gurantee that the code will never change as could happen with some new optimisation). The simulation of TMR0 works like the hardware Regards Dave <{POST_SNAPBACK}> Dave, you say that the simulator works just like the hardware. Than if the hardware takes 2 clock cycles for a write operation onto tmr0, your simulator too must take 2 clock cycles. Am I right? Raghunathan.
  5. I confess i am new to c pogramming, but found it very simple to implement it here. Why sould you reset the timer in the ISR. The ISR should just update the necessary flags. The most important of which is the timer over flow flag(intcon.2). <{POST_SNAPBACK}> Hmm this differs slightly from what the datasheet says and what you do... TMR0IF must be cleared before reenabling the Timer0 Interrupt, nothing about it automatically happening. Looking at your code i expect that the timer will run once and then stop. If the datasheet is right then as soon as you enter the TMR0 interrupt you should clear the flag and reenable it so that it runs again right away with the instruction losses for the ISR calculated in. Used to using Timer1 myself on chips that need a counter reload everytime so this is a normal process to me <{POST_SNAPBACK}> Hi emte, My code works beautifully on the simulator. TMR0IF is the the same as intcon.2, we also call it as timer0 over flow flag( also called timer0 interrupt flag). I have cleared this flag at the end of the code in the ISR(interrupt service routine) void interrupt(void). Hi cac001, If your talking of + or - 3 clock pulses, i think my code will do the job or may be better. If the source boost simulator gives an accurate value of the latency in tmr0 upon entering the ISR & if it also gives the right value upon execution of the c code tmr0 += x; Then my clock should be accurate. I think i have one more question for Dave. Dave, you told me that the compiler does not compensate for a write operation on the timer0 but does the simulator compensate for it? I think it compensates for the write operation & also the extra lines of asm code that it would generate for the c instruction tmr0+=x;. cac001, the incrementing of seconds, minutes, hours are generally done in the ISR itself. I am not unique. See Trossin's code. Regards Raghunathan.
  6. Thanks Trossin & Dave. I wanted to do make a beginner level project & so started of with the relatively simpler tmr0 & without having to set the PIR & PIE. I see that i can't ask for more accuracy from it. But after doing so much I think i should go a little further and implement timer2 for more accuracy. Emte, Yes. The data sheet says if tmr0 is written(add to or subtracted from or just write a new value), the increment of the timer is inhibited for the following two clock cycles. ie. to say it takes 2micro seconds( in our case with 4mhz crystal) for the timer0 to get your value on its register. I confess i am new to c pogramming, but found it very simple to implement it here. Why sould you reset the timer in the ISR. The ISR should just update the necessary flags. The most important of which is the timer over flow flag(intcon.2). I don't stop the timer. It starts running as soon as you set the option register. And it sets the over flow flag when ever the the tmr0 rolls over from 255 to 0. There is no question of resetting your timer. With out any write operation the timer0 will clock 256 microsecons(4mhz crystal) on every interrupt(at every roll over). We just have to see that it gives us an interrut at every 250 microsecond for which we advance the tmr0 by 6micro(256-6) or add 6 to timer0(tmr0+=6;). I think that explains your doubt. On implimenting i faced with problem & thats explained in my first post. Regards, Raghunathan.
  7. Hi Guys, I was writing a code for a clock project using timer0. This project is for my thread "programming pic micro using Boostc". The chip I am using is Pic16F72 with 4mhz crystal. It will display seconds minutes & hours. Two switches connected to portc is used for setting the clock. The prescaler is assigned to wdt, so the timer0 increments every clock cycle ie. 1micro second. This subject has already been discussed in previous threads. Yet i need to get more information. Now i need to measure 250micro seconds. Initially i load the timer0 with 6 and start the timer. Then in interrupt service routine my logic says i need to add 6 to the timer zero value to the already elapsed time in the timer0 register ( this elapsed time is due to the latency in the interrupt hander to save all sfr and then enter the service routine). I also realise from reading the data sheet of microchip that every write operation into tmr0 will cause a delay of 2 clock cycles, which in our case is 2micro seconds. So in theory i need to add 2 more into timer, which equals a value of 8. But when i added 8 into the tmr0 and stepped thro' the code in the simulator i realised that the timer0 register value was much different then i anticipated. The typical value on tmr0 on entering the ISR was 16. Now inorder to get the exact increment i have used tmr0+=2;. on executing this line of c code on the simulator the tmr0 shows 22. Now i have the following questions. 1. Does the compiler automatically correct for the addition into timer0 ? 2. Is the value shown by the tmr0 register in the simulator accurate? 3. Will the time taken (latency time) to enter the ISR be always same in a given code ? My code.. /*This code may initially look more convoluted with the function sec(), min(),hrs(),but you will soon see how advantagious it would be to call them only when the data gets updated & rest of the time we simply display the old value of data.By doing this we get a flicker free display. */ #include <system.h> // Set configuration word #pragma CLOCK_FREQ 4000000 #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF /*all the below variables are made global for easy access in our functions.*/ bit updatesec; bit updatemin; bit updatehrs; unsigned char seconds; unsigned char minutes; unsigned char hours; unsigned char unitsec; unsigned char tensec; unsigned char unitmin; unsigned char tenmin; unsigned char unithrs; unsigned char tenhrs; //timer0 interrupt service routine. void interrupt( void ) { unsigned char tick; unsigned char tick1; unsigned char seconds; unsigned char minutes; unsigned char hours; tmr0 +=2; tick++; if(tick>19) { tick=0; tick1++; if(tick1>199) { tick1=0; seconds++; //a flag to indicate that seconds has been updated updatesec=1; if(seconds>59) { seconds=0; minutes++; //a flag to indicate that minutes has been updated updatemin=1; if(minutes>59) { minutes=0; hours++; //a flag to indicate that hours has been updated updatehrs=1; if(hours>23) { hours=0; } } } } } intcon.2=0; //clear TMR0 overflow flag } //function to get segment values. unsigned char get_value(unsigned char y) { unsigned char segments[10]={0xDE,0x50,0xE6,0xF4,0x78,0xBC,0xBE,0x54,0xFE,0xFC}; return segments[y]; } //a function to get tens & units place for seconds. void sec(void) { tensec = get_value(seconds/10); unitsec= get_value(seconds%10); } //a function to get tens & units place for minutes. void min(void) { tenmin = get_value(minutes/10); unitmin = get_value(minutes%10); } //a function to get tens & units place for hours. void hrs(void) { tenhrs = get_value(hours/10); unithrs = get_value(hours%10); } //main program starts here. void main() { unsigned char a; trisb = 0; //configure port B portb = 0; //clear port B //portc.7 & portc.6 are made as inputs & the rest as outputs. trisc = 0b11000000; portc = 0; while(1) { //set time delay_s(1); //if both switches are closed start clock. if(portc.6 == 0 && portc.7 == 0) { goto clock; } //if switch in portc.6 is pressed increment minutes if(portc.6 == 0) { minutes++; if(minutes>59) { minutes=0; } } //call function min() to get units & tens value for minutes. min(); for(a=0;a<250;a++) { portb = unitmin; portc.2=1; delay_ms(2); portc.2=0; portb = tenmin; portc.3=1; delay_ms(2); portc.3=0; } //again check for both switches to be closed. if(portc.6 == 0 && portc.7 == 0) { goto clock; } //if switch in portc.7 is pressed increment hours. if(portc.7 == 0) { hours++; if(hours>23) { hours=0; } } //call function min() to get units & tens value for hours. hrs(); for(a=0;a>250;a++) { portb = unithrs; portc.4=1; delay_ms(2); portc.4=0; portb = tenhrs; portc.5=1; delay_ms(2); portc.5=0; } if(portc.6 == 0 && portc.7 == 0) { goto clock; } } //start clock clock: updatesec=1; updatemin=1; updatehrs=1; //assign prescaler to wdt & start tmr0. option_reg = 8; // enable interrupts intcon.5=1; //enable tmr0 overflow interrupt intcon.7=1; //enable global interrupt //set tmr0 to genterate interrupt at every 250us. tmr0=6; while( 1 ) //endless loop { if(updatesec==1) //check for update flag,if set { updatesec=0; //clear the flag & call function sec sec(); // to get units & tens value } //for seconds. for(a=0;a<60;a++) { portb = unitsec; portc.0=1; } portc.0=0; for(a=0;a<60;a++) { portb = tensec; portc.1=1; } portc.1=0; if(updatemin==1) { updatemin=0; min(); } for(a=0;a<60;a++) { portb = unitmin; portc.2=1; } portc.2=0; for(a=0;a<60;a++) { portb = tenmin; portc.3=1; } portc.3=0; if(updatehrs==1) { updatehrs=0; hrs(); } for(a=0;a<60;a++) { portb = unithrs; portc.4=1; } portc.4=0; for(a=0;a<60;a++) { portb = tenhrs; portc.5=1; } portc.5=0; } } Regards, Raghunathan.
  8. Hi cac001, I prefer using the At89c2051 to do my timing requirements. I use the bascom basic compiler. Its got a cool feature called auto reload, in which timer0 register gets automatically reloaded with the required value. Say you want an interrupt every 250 micro seconds( if crystal freq,f=12mhz then clock freq=f/12=1mhz, for 2051),the auto reload feature pre loads the timer0 to 6. When the timer0 over flows & an interrupt occurs, the timer0 register is instantaneously loaded to 6 even before it saves all the registers & special function registers(sfr) and enters the interrupt service routine(isr), there by you dont miss any tick. This feature is not there with our Pics and we need to manually load the timer0 value. This being the case is it o.k to preload the timer0 to 6 and then on every interrupt we add 6 to the timer0 ( over flow that was caused due to the lattency in saving those files etc.) register in the interrupt service routine(isr)? Is this the way you have done in your program? Should it be 6 or 7, if it takes 1mico(one clock cycle) to add value to the timer0 register? Regards Raghunathan.
  9. /* thermometer2.c This project is similar to the previous thermometer project, the only difference is that we will be using the internal analog to digital converter of the PIC16F72 microcontroller.The PIC16F72 has 5 channel 8 bit adc and 2k program memory.We will learn how to set the various registers that controls the analog to digital conversion. ANALOG-TO DIGITAL CONVERTER(A/D) MODULE OF PIC16F72. The a/d converter module has five inputs for PIC16F72. The adc allows conversion of an analog input signal to a corresponding 8-bit digital number ie. it outputs values 0-255.The analog reference voltage is soft- ware selectable to either the device's positive supply voltage(vdd)or the voltage on the RA3/vref pin. The adc module has three registers associated with it. They are, 1) a/d result register------------adres 2) a/d control register0----------adcon0 3) a/d control register1----------adcon1 Now let's see the individual registers and how to configure them. adcon0(address 0x1F)-----This information is built into your compiler and gets selected as soon as you slect the chip in the tool bar of your IDE. adcon0 is an 8-bit control register as you all know.Let's see the function of each of its bits & how we should set them. bit7-6........ADCS<1:0>:a/d conversion clock select bits. 00=Fosc/2 01=Fosc/8 10=Fosc/32 11=Frc(clock derived from the internal a/d module RC oscillator) *IN THIS PROJECT WE USE 4MHZ CRYSTAL SO WE CHOOSE Fosc/8* bit5-3........CHS<2:0>:analog channel select bits. 000=channel 0,(RA0/AN0) 001=channel 1,(RA1/AN1) 010=channel 2,(RA2/AN2) 011=channel 3,(RA3/AN3) 100=Channel 4,(RA4/AN4) *IN THIS PROJECT WE CHOOSE ONLY CHANNEL 0(RA0)* bit2..........GO/DONE:a/d conversion status. First to check the status of this bit,you must set ADON bit(coming next) to 1. If ADON=1: 1=a/d conversion in progress(setting this bit starts a/d conversion). 0=a/d conversion completed or conversion not in progress.(this bit is automatically cleared by the hardware when the a/d conversion is complete). bit1...........unimplemented,read as 0. bit0...........ADON:a/d on bit. 1=a/d converter is working. 0=a/d converter is shut off. So in our c program we configure adcon0 as adcon0=0b01000001; adcon1:a/d control register1(address 0x9F)-----This information is built into your compiler and gets selected as soon as you slect the chip in the tool bar of your IDE. bits7-3........unimplented,read as 0. bits2-0........PCFG<2:0>:a/d port configuration control bits. PCFG2:PCFG0.....RA0....RA1....RA2....RA5....RA3....VREF .........000.............A........A.......A........A........A........VDD .........001.............A........A.......A........A........VREF...RA3 .........010.............A........A.......A........A........A........VDD .........011.............A........A.......A........A........VREF...RA3 .........100.............A........A.......D........D........A........VDD .........101.............A........A.......D........D........VREF...RA3 .........11x.............D........D......D........D........D........VDD A=Analog input D=Digital i/o. *IN THIS PROJECT WE CHOOSE RA0,RA1,RA2 PINS AS ANALOG INPUTS & RA3 AS +VREF.* So in our c program we write adcon1=1; The adres register contains the result of the a/d conversion.When a/d conversion is complete,the result is loaded into the adres register, and the GO/DONE bit(adcon0.2)is cleared. PIC16F72 is a 28 pin chip with porta,portb,portc.In this project i have used portc pins to drive the transistor(base) connected to each of the units,tens & hundreds segment ie. to demultiplex data. The segments are connected to portb, similar to our previous project. The units segment like in the previous project is inverted to display "°C". Porta is set for analog mode.The LM35's signal out pin is connected to pin RA0.Pin RA3 is connected to the center arm of a 5k pot. The other two ends of the pot are connected to vdd and ground respectively. Circuit Connections: PIC16F72 pin1- MCLR pin to +5v via 4.7K resistor. pin9-10 4mhz crystal(across pin 9 & 10). connect 22pf capacitors( between pin9 & gnd, pin10 & gnd). pin21-RB0-connect to segment decimal point via 470 ohms. pin22-RB1-connect to segment "e" of the 7-segment display via 470 ohms. pin23-RB2-connect to segment "a" of the 7-segment display via 470 ohms. pin24-RB3-connect to segment "f" of the 7-segment display via 470 ohms. pin25-RB4-connect to segment "c" of the 7-segment display via 470 ohms. pin26-RB5-connect to segment "g" of the 7-segment display via 470 ohms. pin27-RB6-connect to segment "b" of the 7-segment display via 470 ohms. pin28-RB7-connect to segment "d" of the 7-segment display via 470 ohms. pin20-connect to +5v supply. pin8- connect to ground. Base of transistor(U) is connected to RC2(pin13 of micro) via 2.2k resistor. Base of transistor(T) is connected to RC1(pin12 of micro) via 2.2k resistor. Base of transistor(H) is connected to RC0(pin11 of micro) via 2.2k resistor. CONNECTING TEMPERATURE SENSOR LM35 TO PIC16F72. If LM35 is in TO92 pack,then its pin1 is +5 & pin3 is ground.Please see data sheet.Pin 2 of LM35 is connected to RA0(pin2)of 16F72. FIXING THE REFERENCE VOLTAGE. We have programmed RA3 to be the +vref pin. So connect the centre arm of a 5k pot to the RA3 pin(pin5). The other two ends of the pot are connected to vdd and ground respectively. Using a precision multimeter,adjust the 5k pot connected to the +vref pin so that the voltage between RA3 to around is 2.55volts.This will make cal- culations much easy for us. Now when the analog signal input is 2.55volts the adc will out decimal 255. Our step resolution becomes 2.55 divided by 255, which is 0.01volts.ie.for every increment of 0.01volt in the analog signal the adc value will increment by one. Our temperature sensor can be used in the region of 0 to 150°C. At 0°C the analog output is roughly zero and at 150°C its 150mv.The output varies line- arly by 10mv for an increment of 1°C. Seven segment modules. The segment pins of the three 7-segment module must be paralled,ie. all "a" segments are connected together & all "b" segments are connected & so on. Let's call them the units digit,tens digit & hundreds digit. Common cathode of units digit is connected to transistor(U)'s collector. Emitter of transistor(U) is connected to ground. Base of transistor(U) is connected to RC2(pin13 of micro) via 2.2k resistor. Common cathode of tens digit is connected to transistor(T)'s collector. Emitter of transistor(T) is connected to ground. Base of transistor(T) is connected to RC1(pin12 of micro) via 2.2k resistor. Common cathode of hundreds digit is connected to transistor(H)'s collector. Emitter of transistor(H) is connected to ground. Base of transistor(H) is connected to RC0(pin11 of micro) via 2.2k resistor. Transistor type-BC 547 NPN. */ #include <system.h> #pragma CLOCK_FREQ 4000000 // config clock to 4mhz. // Set configuration fuse. #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF //A function to get adc value from pic's built-in adc. void a_d(void); //A function for 7-segment display to display "0°C-99°C". void seven_segment1(void); //A function for 7-segment display to dispaly "0-150". void seven_segment2(void); //A function to get segment values for hundreds & tens. unsigned char get_value1(unsigned char x); //A function to get segments value for units. //unit's display module is inverted so as to display degree celsius, //with decimal point at top of the display. unsigned char get_value2(unsigned char y); /*Variable adc is made global for easy access, which is used in main().*/ unsigned char adc; //Variable temperature is made global for easy access. unsigned char temperature; void main() { trisa=255; //set porta as input. trisb=0; //set all portb pins as output. trisc=0; //set all portc pins as output pins. portc=0; //make all portc pins low. portb=0; //zero all portb pins. /* make RA0,RA1,RA2 pins as analog inputs & RA3 as +ref.*/ adcon1=1; /*choose Fosc/8,RA0/AN0 as channel(0),go/done=0,adon=1.*/ adcon0=0b01000001; unsigned int sample; //sample var holds the adc sample value. unsigned char b0; //for loop var. while( 1 ) //Infinite loop. { sample=0; //initialize the sample to zero. for(b0=0;b0<20;b0++) //take 20 adc samples. { a_d(); //call function a_d(). sample += adc; } temperature=sample/20; //take average of 20 samples. if(temperature<99) //call seven_segment1 if temperature is less seven_segment1(); //than 99 else call seven_segment2. else seven_segment2(); } } void a_d(void) //adc routine. { adc=0; adcon0.2=1; //start ad conversion. while(adcon0.2==1) //check if conversion is complete. { } adc=adres; //if conversion is over, load adc value. } void seven_segment1(void) //seven_segment1 routine. { unsigned char b0; //b0 as for loop counter. unsigned char tens; //holds the tens value to be displayed unsigned char units; //holds the units value. tens=temperature/10; //find the tens value. units=temperature%10; //find the units value. for(b0=0;b0<250;b0++) //loop it 250 times to see. { portb=get_value1(tens); //place the segment value of tens on portb portc.0=1; //turn on transistor(H). delay_ms(1); //keep it on for 1ms. portc.0=0; //turn off transistor(H). portb=get_value1(units); //place the segment value of units. portc.1=1; //turn on transistor(T). delay_ms(1); //keep it on for 1ms. portc.1=0; //turn it off. portb=0xD5; //place character "°C" to represent degree celsius. portc.2=1; //turn on transistor(U). delay_ms(1); //keep it on for 1ms. portc.2=0; //turn it off. } } void seven_segment2(void) //seven_segment2 routine. { unsigned char b0; //same as above with the only difference unsigned char hundreds; //in the units segment which in this case unsigned char tens; // will display the units value instead of unsigned char units; // character "C". i wish to remind you that hundreds=temperature/100; //the this display is inverted & so tens=(temperature%100)/10; //requires a diffrent set of segment units=temperature%10; //values.This we do by calling get_value2 for(b0=0;b0<250;b0++) { portb=get_value1(hundreds); portc.0=1; delay_ms(1); portc.0=0; portb=get_value1(tens); portc.1=1; delay_ms(1); portc.1=0; portb=get_value2(units); portc.2=1; delay_ms(1); portc.2=0; } } unsigned char get_value1(unsigned char x) { unsigned char segments[10]={0xDE,0x50,0xE6,0xF4,0x78,0xBC,0xBE,0x54,0xFE,0xFC}; return segments[x]; } unsigned char get_value2(unsigned char y) { unsigned char segments[10]={0xDE,0x0A,0xE6,0xAE,0x3A,0xBC,0xFC,0x8A,0xFE,0xBE}; return segments[y]; } /* In this project we configured the hardware registers of the A to D converter.See how we do a software polling of pin adcon0.2 to see if a/d conversion is complete. If we want we can even configure the adc interrupt bits.So that once the a/d conversion is complete an interrupt is generated. The bits associated with this interrupt are clear ADIF bit set ADIE bit set GIE bit. Try doing this & have lots of fun. */
  10. Actually the pic will out 0 to 1023 decimal. 0 when the analog input is zero volts and 1023 when the analog input equals the +vref voltage. Why should you use a multimeter when your micro can read the value? You can't read 220 volts, and if you do connect it you can see thick fumes coming out. you need to drop this voltage with the suitable divider and feed it into the analog input, making sure the input voltage doesn't exeed the +vref voltage or atleast vcc of the pic micro. vref can either be made equal to Vcc or you can set it manually by adjusting the RA3 pin which is generally made +vref pin. To choose the appropriate vref you need to set adcon1 bits<2:0>. Once the vref is chosen, your range now becomes vref divided by 1023.ie, your resolution. If you choose 5 volts as your ref then your resolution becomes 5/1023. if you choose 2.5volts as your vref(by adjusting a pot connected to the vref pin(RA3)) then your resolution becomes 2.5/1023 and so on. as in the above example if 220 volts was scaled down to 5 volts and with vref made equal to vcc(5v), then your pic will out 1023 when the input voltage is 220. Your step resolution on the 220 volts side becomes 220/1023=0.2150. Suppose your pic outs 100 decimal then your voltage will be 0.215*100=21.5volts. you can use the floating point lib function to do the calculation and display it on your lcd.
  11. Hi guys, I had just completed the thermometer project using Pic16f72. I will soon be posting it in my thread "pic micro programming in boostC for beginners. I am yet to write the detailed description for the circuit connections & its functioning. I will post the code here, see if its useful for you. Unlike many programs in BoostC which use set_bit clear_bit macros, i straight away write the config bits into the respective SFR. Have look at this code. #include <system.h> #pragma CLOCK_FREQ 4000000 // config clock to 4mhz. // Set configuration fuse. #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF //A function to get adc value from pic's built-in adc. void a_d(void); //A function for 7-segment display to display "0°C-99°C". void seven_segment1(void); //A function for 7-segment display to dispaly "0-150". void seven_segment2(void); //A function to get segment values for hundreds & tens. unsigned char get_value1(unsigned char x); //A function to get segments value for units. //units display module is inverted so as to display degree celsius, //with decimal point at top of the display. unsigned char get_value2(unsigned char y); /*Variable adc is made global for easy access, which is used in main().*/ unsigned char adc; //Variable temperature is made global for easy access. unsigned char temperature; void main() { trisa=255; //set porta as output. trisb=0; //set porb.0 as input & rest of the pins as output. trisc=0; //set all portc pins as output pins. portc=0; //make all portc pins low. portb=0; //zero all portb pins. adcon1=1; // make RA0,RA1,RA2 pins as analog inputs & RA3 as +ref. adcon0=0b01000001; //choose Fosc/8,RA0/AN0 as channel(0),go/done=0,adon=1. unsigned int sample; //sample var holds the adc sample value. unsigned char b0; //for loop var. while( 1 ) //Infinite loop. { sample=0; //initialize the sample to zero. for(b0=0;b0<20;b0++) //take 20 adc samples. { a_d(); //call function a_d(). sample += adc; } temperature=sample/20; //take average of 20 samples. if(temperature<99) //call seven_segment1 if temperature is less seven_segment1(); //than 99 else call seven_segment2. else seven_segment2(); } } void a_d(void) //adc routine. { adc=0; adcon0.2=1; //start ad convertion. while(adcon0.2==1) //check if conversion is complete. { } adc=adres; //if conversion is over, load adc value. } void seven_segment1(void) //seven_segment1 routine. { unsigned char b0; //b0 as for loop counter. unsigned char tens; //holds the tens value to be displayed unsigned char units; //holds the units value. tens=temperature/10; //find the tens value. units=temperature%10; //find the units value. for(b0=0;b0<250;b0++) //loop it 250 times to see. { portb=get_value1(tens); //place the segment value of tens on portb portc.0=1; //turn on transistor(H). delay_ms(1); //keep it on for 1ms. portc.0=0; //turn off transistor(H). portb=get_value1(units); //place the segment value of units. portc.1=1; //turn on transistor(T). delay_ms(1); //keep it on for 1ms. portc.1=0; //turn it off. portb=0xD5; //place character "°C" to represent degree celsius. portc.2=1; //turn on transistor(U). delay_ms(1); //keep it on for 1ms. portc.2=0; //turn it off. } } void seven_segment2(void) //seven_segment2 routine. { unsigned char b0; //same as above with the only difference unsigned char hundreds; //in the units segment which in this case unsigned char tens; // will display the units value instead of unsigned char units; // character "C". i wish to remind you that hundreds=temperature/100; //the this display is inverted & so tens=(temperature%100)/10; //requires a diffrent set of segment units=temperature%10; //values.This we do by calling get_value2 for(b0=0;b0<250;b0++) { portb=get_value1(hundreds); portc.0=1; delay_ms(1); portc.0=0; portb=get_value1(tens); portc.1=1; delay_ms(1); portc.1=0; portb=get_value2(units); portc.2=1; delay_ms(1); portc.2=0; } } unsigned char get_value1(unsigned char x) { unsigned char segments[10]={0xDE,0x50,0xE6,0xF4,0x78,0xBC,0xBE,0x54,0xFE,0xFC}; return segments[x]; } unsigned char get_value2(unsigned char y) { unsigned char segments[10]={0xDE,0x0A,0xE6,0xAE,0x3A,0xBC,0xFC,0x8A,0xFE,0xBE}; return segments[y]; } Raghunathan
  12. Hi guys, Will this work? Instead of using two 16 bit registers temp1 & temp2, why dont we load it directly? let's say the adc result is right justified. then result=adresl; result.8=adresh.0; result.9=adresh.1; Raghunathan.
  13. Hi cac001, PIC16F876 has got both adc and comparator connected to porta. The cmcon register is by default sets to off or 7 on POR. So on power-on reset (POR) porta gets configured as analog input for the adc. In order to change it to digital you should config adcon1 to 7. Regards Raghunathan
  14. Hi, As far as i know PIC16F876 is a 28 pin chip. To see your leds work on porta make adcon1=7; ie. set it to digital mode. I would suggest you to take a look at the thread "pic micro programming in BoostC for beginners". Regards Raghunathan.
  15. /* Thermometer1.c In our previous program we learnt how to display values on 7-segment display. In this program we make PIC16F84A display temperature read from LM35 tempera- ture sensor.PIC16F84A doesn't have built in analog to digital converter.So we shall use an external analog to digital converter(adc) TLC549.This adc is an serial adc & outputs the adc value serially on its (SDA OUT) pin6. A little information about analog and digital signals. An analog signal is infinitely variable between any two of its measuring points, no matter how close the two measuring points may be.For example, the number of possible readings between 1volt and 2 volts are infinite. similarly between 1volt and 1.0001volt we can have infinite values of vol- tages like 1.000001 or 1.000000001volts & so on.So we can have infinitesi- mally varying values of voltages. A digital signal equivalent of an analog signal is not infinitely variable. The digital equivalent of an analog signal varies in step proportion deter- mined by the resolution of the a/d converter. Lets take a typical example. suppose we have an anolog signal which varies from 0 to 5volts. and suppose we use an 8 bit adc, then the resolution of our converter is 256(8 bit values) or the adc will typically return values from 0 to 255.The adc will return 0 if it finds a analog voltage value of 0 and return 255 if it finds an analog voltage of 5volts (provided the reference to the adc is +5volts). step resolution of the converter is the step increment in the analog value for a step change in digital signal.In our above case its 5volts divided by 255(not 256) which is 0.0196volts.Which means that when ever the analog vol- tage changes by 0.0196volts the adc will increment its digital output value by 1. some adc values for the analog inputs for the above example are analog value--------------adc value 0volts-------------------------0 0.0196v-----------------------1 0.0392v-----------------------2 0.0588v-----------------------3 ......................................... ......................................... 5.0v---------------------------255 Some information about LM35 temperature sensor. NATIONAL SEMICONDUCTORS LM35 DATA SHEET LM35 Precision Centigrade Temperature Sensors General Description The LM35 series are precision integrated-circuit temperature sensors, whose output voltage is linearly proportional to the Celsius (Centigrade) temperature. The LM35 thus has an advantage over linear temperature sensors calibrated in ° Kelvin, as the user is not required to subtract a large constant voltage from its output to obtain convenient Centigrade scaling. The LM35 does not require any external calibration or trimming to provide typical accuracies of ±1/4°C at room temperature and ±3/4°C over a full -55 to +150°C temperature range. Low cost is assured by trimming and calibration at the wafer level. The LM35’s low output impedance, linear output, and precise inherent calibration make interfacing to readout or control circuitry especially easy. It can be used with single power supplies, or with plus and minus supplies. As it draws only 60 µA from its supply, it has very low self-heating, less than 0.1°C in still air. The LM35 is rated to operate over a -55° to +150°C temperature range, while the LM35C is rated for a -40° to +110°C range (-10° with improved accuracy). The LM35 series is available packaged in hermetic TO-46 transistor packages, while the LM35C, LM35CA, and LM35D are also available in the plastic TO-92 transistor package. The LM35D is also available in an 8-lead surface mount small outline package and a plastic TO-220 package. Features 1 Calibrated directly in ° Celsius (Centigrade) 2 Linear + 10.0 mV/°C scale factor 3 0.5°C accuracy guaranteeable (at +25°C) 4 Rated for full -55° to +150°C range 5 Suitable for remote applications 6 Low cost due to wafer-level trimming 7 Operates from 4 to 30 volts 8 Less than 60 µA current drain 9 Low self-heating, 0.08°C in still air 10 Nonlinearity only ±1/4°C typical 11 Low impedance output, 0.1 W for 1 mA load In our project we will use the sensor in the range of0°C-150°C. Some information about Texas Instruments TLC549 serial adc . TLC549 data sheet. Microprocessor Peripheral or Standalone Operation 8-Bit Resolution A/D Converter Differential Reference Input Voltages Conversion Time . . . 17 ms Max Total Access and Conversion Cycles Per Second TLC548 . . . up to 45 500 TLC549 . . . up to 40 000 On-Chip Software-Controllable Sample-and-Hold Function Total Unadjusted Error . . . ±0.5 LSB Max 4-MHz Typical Internal System Clock Wide Supply Range . . . 3 V to 6 V Low Power Consumption . . . 15 mW Max Ideal for Cost-Effective, High-Performance Applications including Battery-Operated Portable Instrumentation Pinout and Control Signals Compatible With the TLC540 and TLC545 8-Bit A/D Converters and with the TLC1540 10-Bit A/D Converter CMOS Technology description The TLC548 and TLC549 are CMOS analog-to-digital converter (ADC) integrated circuits built around an 8-bit switched-capacitor successive-approximation ADC. These devices are designed for serial interface with a microprocessor or peripheral through a 3-state data output and an analog input. The TLC548 and TLC549 use only the input/output clock (I/O CLOCK) input along with the chip select (CS) input for data control.The maximum I/O CLOCK input frequency of the TLC548 is 2.048 MHz, and the I/O CLOCK input frequency of the TLC549 is specified up to 1.1 MHz. For certain applications, such as strobing applications, it is necessary to start conversion at a specific point in time.This device accommodates these applications. Although the on-chip sample-and-hold function begins sampling upon the high-to-low transition of the fourth I/O CLOCK cycle, the hold fun- ction does not begin until the high-to-low transition of the eighth I/O CLO- CK cycle, which should occur at the moment when the analog signal must be converted. The TLC548 and TLC549 continue sampling the analog input until the high-to-low transition of the eighth I/O CLOCK pulse. The control circu- itry or software then immediately lowers I/O CLOCK and starts the holding f- unction to hold the analog signal at the desired point in time and starts the conversion. Circuit Connections: PIC16F84 pin4- MCLR pin to +5v via 4.7K resistor. pin15-16 4mhz crystal(across pin 15 & 16). connect 22pf capacitors( between pin15 & gnd, pin16 & gnd). pin6-RB0-no connection. pin7-RB1-connect to segment "e" of the 7-segment display via 470 ohms. pin8-RB2-connect to segment "a" of the 7-segment display via 470 ohms. pin9-RB3-connect to segment "f" of the 7-segment display via 470 ohms. pin10-RB4-connect to segment "c" of the 7-segment display via 470 ohms. pin11-RB5-connect to segment "g" of the 7-segment display via 470 ohms. pin12-RB6-connect to segment "b" of the 7-segment display via 470 ohms. pin13-RB7-connect to segment "d" of the 7-segment display via 470 ohms. pin14-connect to +5v supply. pin5- connect to ground. Base of transistor(U) is connected to RA2(pin1 of micro) via 2.2k resistor. Base of transistor(T) is connected to RA1(pin18 of micro) via 2.2k resistor. Base of transistor(H) is connected to RA0(pin17 of micro) via 2.2k resistor. TLC549 connections: pin1(Ref+)- connect this pin to the center or variable terminal or pin of a 5k potentiometer. Connect one end of the pot to +5v and other to the ground. pin2(Analog input)- connect this pin to LM35 signal out pin.If LM35 is TO92 package,its the center lead.other two pins of LM35 is given to +5v and ground. Again if LM35 is in TO92 pack then its pin1 is +5 & pin3 is ground.Please see data sheet. pin3(Ref-)- connect this pin to ground. pin4(Gnd)- connect to ground. pin5(CS)- chip select pin is active low.connect this pin to RA3(pin2 of 16f84). pin6(Data out)- connect this pin to RB0(pin6 of 16f84). pin7(i/o clock)- connect this pin to RA4(pin3 of 16f84). Note- Pin RA4 is open drain & so use a 1k pullup resistor to +5v. pin8(Vcc)- connect to +5volts. FIXING THE REFERENCE VOLTAGE. Using a precision multimeter,adjust the 5k pot connected to the Ref+ pin of TLC549 to around 2.55volts.This will make calculations much easy for us. Now when the analog signal input is 2.55volts the adc will out decimal 255. Our step resolution becomes 2.55 divided by 255, which is 0.01volts.ie.for every increment of 0.01volt in the analog signal the adc value will increment by one. Our temperature sensor can be used in the region of 0 to 150°C. At 0°C the analog output is roughly zero and at 150°C its 150mv.The output varies line- arly by 10mv for an increment of 1°C. Seven segment modules. The segment pins of the three 7-segment module must be paralled,ie. all "a" segments are connected together & all "b" segments are connected & so on. Let's call them the units digit,tens digit & hundreds digit. Common cathode of units digit is connected to transistor(U)'s collector. Emitter of transistor(U) is connected to ground. Base of transistor(U) is connected to RA2(pin1 of micro) via 2.2k resistor. Common cathode of tens digit is connected to transistor(T)'s collector. Emitter of transistor(T) is connected to ground. Base of transistor(T) is connected to RA1(pin18 of micro) via 2.2k resistor. Common cathode of hundreds digit is connected to transistor(H)'s collector. Emitter of transistor(H) is connected to ground. Base of transistor(H) is connected to RA0(pin17 of micro) via 2.2k resistor. Transistor type-BC 547 NPN. One main difference between this project's display schematic & the previous is that in this project we invert the units display module.Please note we only physically rotate the module through 180° but the electrical connections remain the same. We do this so that the decimal point in the segment appears to the top left position, so that we can create the character "°C". Until the temperature of 99 the units digits will display "°C",beyond 99 it will display all three decimal digits.Since the last digit is inverted i have used a seperate set of segment values or lookup table for it. When i finished programming i realized that i had no pin left to connect the decimal point in the units segment. So i decided to directly connect this pin to +5volts via 470 ohms. The only odd thing is that it will be lit even while displaying temperatures beyond 99°C. */ #include <system.h> #pragma CLOCK_FREQ 4000000 // config clock to 4mhz. // Set configuration fuse. #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF #include <system.h> //A function to create clock pulse for TLC549 void clk(void); //A function to get adc value serially from TLC549 void serial_adc(void); //A function for 7-segment display to display "0°C-99°C". void seven_segment1(void); //A function for 7-segment display to dispaly "0-150". void seven_segment2(void); //A function to get segment values for hundreds & tens. unsigned char get_value1(unsigned char x); //A function to get segments value for units. //units display module is inverted so as to display degree celsius, //with decimal point at top of the display. unsigned char get_value2(unsigned char y); /*Variable adc is made global for easy bit access in serial_adc() function which is used in main().*/ unsigned char adc; //Variable temperature is made global for easy access. unsigned char temperature; void main() { trisa=0; //set porta as output. trisb=1; //set porb.0 as input & rest of the pins as output. portb=0; //zero all portb pins. porta=8; // make chip select pin of TLC549 high. unsigned int sample; //sample var holds the adc sample value. unsigned char b0; //for loop var. while( 1 ) //Infinite loop. { sample=0; //initialize the sample to zero. for(b0=0;b0<20;b0++) { serial_adc(); sample += adc; } temperature=sample/20; if(temperature<99) //call seven_segment1 if temperature is less seven_segment1(); //than 99 else call seven_segment2. else seven_segment2(); } } void serial_adc(void) //serial_adc routine. { adc=0; porta.3=0; // bring chip select low to start adc. adc.7=portb.0; //load the most significant bit of adc. clk(); //send clock pulse to get the next adc bit. adc.6=portb.0; //load it onto the next significant bit. clk(); // & so on until the last adc bit. adc.5=portb.0; clk(); adc.4=portb.0; clk(); adc.3=portb.0; clk(); adc.2=portb.0; clk(); adc.1=portb.0; clk(); adc.0=portb.0; clk(); porta.3=1; } void clk(void) //The clock routine. { porta.4=1; //Make porta.4 high. porta.4=0; //Make porta.4 low. } void seven_segment1(void) //seven_segment1 routine. { unsigned char b0; //b0 as for loop counter. unsigned char tens; //holds the tens value to be displayed unsigned char units; //holds the units value. tens=temperature/10; //find the tens value. units=temperature%10; //find the units value. for(b0=0;b0<250;b0++) //loop it 250 times to see. { portb=get_value1(tens); //place the segment value of tens on portb porta.0=1; //turn on transistor(H). delay_ms(1); //keep it on for 1ms. porta.0=0; //turn off transistor(H). portb=get_value1(units); //place the segment value of units. porta.1=1; //turn on transistor(T). delay_ms(1); //keep it on for 1ms. porta.1=0; //turn it off. portb=0xD4; //place character "C" to represent degree celsius. porta.2=1; //turn on transistor(U). delay_ms(1); //keep it on for 1ms. porta.2=0; //turn it off. } } void seven_segment2(void) //seven_segment2 routine. { unsigned char b0; //same as above with the only difference unsigned char hundreds; //in the units segment which in this case unsigned char tens; // will display the units value instead of unsigned char units; // character "C". i wish to remind you that hundreds=temperature/100; //the this display is inverted & so tens=(temperature%100)/10; //requires a diffrent set of segment units=temperature%10; //values.This we do by calling get_value2 for(b0=0;b0<250;b0++) { portb=get_value1(hundreds); porta.0=1; delay_ms(1); porta.0=0; portb=get_value1(tens); porta.1=1; delay_ms(1); porta.1=0; portb=get_value2(units); porta.2=1; delay_ms(1); porta.2=0; } } unsigned char get_value1(unsigned char x) { unsigned char segments[10]={0xDE,0x50,0xE6,0xF4,0x78,0xBC,0xBE,0x54,0xFE,0xFC}; return segments[x]; } unsigned char get_value2(unsigned char y) { unsigned char segments[10]={0xDE,0x0A,0xE6,0xAE,0x3A,0xBC,0xFC,0x8A,0xFE,0xBE}; return segments[y]; } /*Whats new in this program? See how the function serial_adc() milks out the adc value bit by bit and stores it. Twenty samples of adc values are taken and is averaged out to get a more stable read out. Try for yourself with different number of samples. You can see two different display routines. One for displaying upto 99°C & another for beyond 99°C.Since the last segment module is inverted in- order to display °C, i had to use a different look table (get_value2()) to put the units value of temperature readings beyond 99. This program compiles to 338 words. You have also got 10bit serial adc chips. Try using them in your projects. Our next project will use the built in adc of the PIC microcontroller. I wish to use PIC16F72. This chip is available for less than a Dollar in my place & so i purchased them.Try downloading its data sheet and go thro- ugh its adc specs & how to configure them. */ PIC33.bmp pic13modified_tlc549_thermometer.bmp
  16. Your using one pin? Your code says your using 5 pins... But i am curious, how are you resolving to +/- 0.1 degree with that small a range ... <{POST_SNAPBACK}> Hi emte, rfhaley is using 5 sensors for the 5 channel adc and thats why its 5 pins. you can set just 1 pin to adc if you want. I don't know if its a 10bit adc or 12 bit adc. any way he is not using adresl. Very soon i will be posting a thermometer project using LM34 sensor on my thread "Pic Micro programming in Boostc for beginners". Just not finding enough time. regards, Raghunathan.
  17. Fred, In fact my sample code as a macro compiles to just 30 words & each addition pulseout statement increases the code just by 5 words. Its just like any other library function used in other compilers like pic basic. Raghunathan.
  18. Hi Fred, Your code compiles to 129 words. I checked it up on the simulator & found no change on the LED. ? . Regards Raghunathan.
  19. That solves my problem. Using macros is a cool feature. But Dave, I did not see this style or syntax in BoostC user's manual. Instead I found template <class T> void foo(T *t) { ..... } Can you please elabrate as to how one could use this syntax in my example code. Thanks, Raghunathan.
  20. Hi Guys, I wanted to create a library function similar to the pulsout command of pic basic compiler. In basic the command is like this pulsout pin, period The pin is any portb pin & period is duration for which it is high. example pulsout portb.0,100 I tried to create this in C using the references as function arguments. Let me quote from the Boost C user manual which says that when such argument changes in side the function the original variable used in the function call changes too. Below is my sample code for pulseout command. #include <system.h> #pragma CLOCK_FREQ 4000000 // config clock to 4mhz. // Set configuration fuse. #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF void pulseout(unsigned char &pin,unsigned char duration); void main() { trisb=0; portb=0; while( 1 ) { pulseout(portb.0,1); } } void pulseout(unsigned char &pin,unsigned char duration) { pin=1; delay_ms(duration); pin=0; } I tried this on the simulator but did not see portb.0 change to 1 when pin=1; gets executed in the pulseout function. But i found that portb.0 takes the value of the last statement executed, In this case its 0. If you make pin=1; as the last statement, port.0 is made 1. Is there any way we can make the original variable change in real time as and when the argument gets changed? There by i can make any port pin to out pulses. Very useful in LCD, SPI etc programs where this function gets called several times. Raghunathan.
  21. /* 3-digit-7-segment_display (Using PIC16F84) In this project we will connect three common cathode 7-segment modules in parallel & then connect them to the 7 pins of portb(RB1thro'RB7) via 470 ohms resistors. In all our future projects we will use RB1 TO RB7 pins for our 7 LEDs of the segment module. We will demultiplex the data to the 7-segment modules by using three transistors connected to the common cathode pin of each of the module. The base of the transistors are driven from porta pins. This project will form the base for our future projects like A/D converter or a digital thermometer, digital clock etc. The C program will display decimal 0 to 999 on the three segments. The program is in a loop and so will continue to display from 0 once again after it reaches the value off 999. We can't use the simulator for this project. So we have to hard wire to see our code work. I have checked it on my board. You can probably use a bread board to test it. Connections: PIC16F84 pin4- MCLR pin to +5v via 4.7K resistor. pin15-16 4mhz crystal(across pin 15 & 16). connect 22pf capacitors( between pin15 & gnd, pin16 & gnd). pin6-RB0-no connection. pin7-RB1-connect to segment "e" of the 7-segment display via 470 ohms. pin8-RB2-connect to segment "a" of the 7-segment display via 470 ohms. pin9-RB3-connect to segment "f" of the 7-segment display via 470 ohms. pin10-RB4-connect to segment "c" of the 7-segment display via 470 ohms. pin11-RB5-connect to segment "g" of the 7-segment display via 470 ohms. pin12-RB6-connect to segment "b" of the 7-segment display via 470 ohms. pin13-RB7-connect to segment "d" of the 7-segment display via 470 ohms. pin14-connect to +5v supply. pin5- connect to ground. Base of transistor(U) is connected to RA2(pin1 of micro) via 2.2k resistor. Base of transistor(T) is connected to RA1(pin18 of micro) via 2.2k resistor. Base of transistor(H) is connected to RA0(pin17 of micro) via 2.2k resistor. Seven segment modules. The segment pins of the three 7-segment module must be paralled,ie. all "a" segments are connected together & all "b" segments are connected & so on. Let's call them the units digit,tens digit & hundreds digit. Common cathode of units digit is connected to transistor(U)'s collector. Emitter of transistor(U) is connected to ground. Base of transistor(U) is connected to RA2(pin1 of micro) via 2.2k resistor. Common cathode of tens digit is connected to transistor(T)'s collector. Emitter of transistor(T) is connected to ground. Base of transistor(T) is connected to RA1(pin18 of micro) via 2.2k resistor. Common cathode of hundreds digit is connected to transistor(H)'s collector. Emitter of transistor(H) is connected to ground. Base of transistor(H) is connected to RA0(pin17 of micro) via 2.2k resistor. Transistor type-BC 547 NPN. */ #include <system.h> #pragma CLOCK_FREQ 4000000 // Set configuration word #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF //declare function get_value. unsigned char get_value(unsigned char y); unsigned char y; unsigned char units; //declare units as unsigned char variable. unsigned char tens; //declare tens as unsigned char variable. unsigned char hundreds; //hundreds as unsigned char variable. void main(void) { trisa=0; //make porta as output. porta=0; //make porta pins low. trisb=0; //make portb as output. portb=0; //make portb pins low. while(1) //endless loop. { unsigned int b0; //declare b0 as unsigned integer variable. unsigned char b1; //declare b1 as unsigned character. for (b0=0;b0<1000;b0++) //for loop to display 0-999. { hundreds=b0/100; //get the hundred's value. tens=(b0%100)/10; //get the ten's value. units=b0%10; //get the unit's value. for (b1=0;b1<100;b1++) //display data hundred times. { portb = get_value(hundreds); //get segment value. porta.0=1; //switch on tranisistor(H). delay_ms(1); //pause 1ms to see data. porta.0=0; //switch off transistor(H). portb=get_value(tens); //get segment value. porta.1=1; //switch on tranisistor(T). delay_ms(1); //pause 1ms to see data. porta.1=0; //switch off transistor(T). portb=get_value(units); //get segment value. porta.2=1; //switch on tranisistor(U). delay_ms(1); //pause 1ms to see. porta.2=0; //switch off transistor(U). } } } } //lookup table for the segment values. unsigned char get_value(unsigned char y) { unsigned char segments[10]={0xDE,0x50,0xE6,0xF4,0x78,0xBC,0xBE,0x54,0xFE,0xFC}; return segments[y]; } /* The C program first intializes the ports as output. Next we enter the while loop where we have created a for loop which will make b0 to take values from 0-999. Next we proceed to determine the hundred's, ten's and unit's value of b0. These values are then passed on to the lookup table which is an array of values. The array contains the segment value that has to be outputted on portb. The values are for "0" to "9" decimal.When this value is outputted on portb, the appropriate leds light up to from the digits. First we output the hundred's value on portb & switch on the transistor(H) connected to the hundreds digit for a brief period of 1ms and then switch it off. Next we place the ten's value on portb and switch on & off the transistor(T) & then we do the same thing for the units value. This is repeated for 100 times so that we can see all the three digits on all the time. Changing the loop value b1 will change the rate at which numbers will appear on the display. You can vary the delay time as well as the loop value b1 to see the effect.See how an array is declare in the function get_value & how the return statement returns the appropriate segment value.All variables are declared as unsigned character in order to save program words.This program compiles to 208 words. */ pic13.bmp pic11modified.bmp
  22. /* BINARY CODED DECIMAL DISPLAY In this project we will display the binary data outputted by the port on two seven segment LED modules. We will make the seven segment display decimal 0 to 99. We can use the 4511 BCD to 7-segment converter IC for our purpose. The lower nibble of portb is connected to one of the 7-seg- ment via 4511 to display the units value & the higher nibble of portb is connected to the second 7-segment via another 4511 to display the tens value. Source Boost IDE has got this plugin on its simulator. So its very easy to verify your code. Connections: pin4- MCLR pin to +5v via 4.7K resistor. pin15-16 4mhz crystal(across pin 15 & 16). connect 22pf capacitors( between pin15 & gnd, pin16 & gnd). lower nibble or units display. pin6-RB0-connect to pin7 of 4511(1). pin7-RB1-connect to pin1 of 4511(2). pin8-RB2-connect to pin2 of 4511(4). pin9-RB3-connect to pin6 of 4511(8). upper nibble or tens display. pin10-RB4-connect to pin7 of 4511. pin11-RB5-connect to pin1 of 4511. pin12-RB6-connect to pin2 of 4511. pin13-RB7-connect to pin6 of 4511. Remaining pin connections of 4511. pin13-to "A" segment of 7-segment via 470 ohms. pin12-to "B" segment of 7-segment via 470 ohms. pin11-to "C" segment of 7-segment via 470 ohms. pin10-to "D" segment of 7-segment via 470 ohms. pin9- to "E" segment of 7-segment via 470 ohms. pin15-to "F" segment of 7-segment via 470 ohms. pin14-to "G" segment of 7-segment via 470 ohms. pin16-to +5v. pin3-to +5v. pin4-to +5v. pin5-to ground. pin8-to ground. 7-segment display-common cathode-to ground. */ #include <system.h> #pragma CLOCK_FREQ 4000000 // config clock to 4mhz. // Set configuration fuse. #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF void main() { trisb=0; //make portb as output. portb=0; //set portb pins to low. char b0; //declare b0 as character type variable. char units; //declare units as character type variable. char tens; //declare tens as character type variable. char bcd; //declare bcd as character type variable. while(1) //endless loop { for(b0=0;b0<100;b0++) //for loop, which outputs 0-99 as BCD. { tens=b0/10; //tens value is first calculated. units=b0%10; //next units value is derived. tens *= 16; //we shift the tens value to the upper nibble. bcd=units+tens; //we add the upper & lower nibble to get BCD value. portb=bcd; //out the BCD value on portb. delay_ms(250); //wait half a second for us to see display. delay_ms(250); } } } /* This program compiles to 91 words. In the above program change all char variables to unsigned char variables and see the program words saved. */
  23. /* BUTTON TEST In this program we make our microcontroller(PIC16F84) to read switches connected to porta which will dynamically modify the program as it runs. We have connected three switches to the porta. We have named them button1, button2, button3. The main program is the scrolling LED program we had seen earlier. Pressing button1 will change the direction in which the LEDs scroll. Pressing butt- on2 will increment the delay time for which the LEDs are lit. pres- sing button3 will reduce the delay time for which the LEDs are lit. Before you load the hex file onto your chip, you can use the built in simulator on the SourceBoost IDE to check if your code is working just as intended.Read the IDE user's manual to get help to configure your plugins. Connections: pin4- MCLR pin to +5v via 4.7K resistor pin15-16 4mhz crystal(across pin 15 & 16) connect 22pf capacitors( between pin15 & gnd, pin16 & gnd) pin6-RB0-connect LED to pin6 via 470 ohms. Cathode of LED to gnd. pin7-RB1-connect LED to pin7 via 470 ohms. Cathode of LED to gnd. pin8-RB2-connect LED to pin8 via 470 ohms. Cathode of LED to gnd. pin9-RB3-connect LED to pin9 via 470 ohms. Cathode of LED to gnd. pin10-RB4-connect LED to pin10 via 470 ohms. Cathode of LED to gnd. pin11-RB5-connect LED to pin11 via 470 ohms. Cathode of LED to gnd. pin12-RB6-connect LED to pin12 via 470 ohms. Cathode of LED to gnd. pin13-RB7-connect LED to pin13 via 470 ohms. Cathode of LED to gnd. pin17-RA0-connect switch, button1. pin18-RA1-connect switch, button2. pin1-RA2-connect switch, button3. There are two different ways in which you can configure your switch. .ie. the switch can output a high when pressed or a low when pressed. Based on this information you need to modify the code in your if statement.But this code works as it is on the simulator. In the future i will provide the schematic for all the projects done here. If you hard wire this project, make sure your micro sees the right switch state. */ #include <system.h> #pragma CLOCK_FREQ 4000000 // Set configuration fuse #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF void check1(void); // declare that you are using a routine // called check1. void check2(void); // declare that you are using a routine // called check2. int duration; // duration is declared as global variable. #define button1 porta.0 // button1 is alais for porta.0 #define button2 porta.1 // button2 is alais for porta.1 #define button3 porta.2 // button3 is alais for porta.2 void main(void) { // Program entry point. trisa=7; // set porta pin0-pin2 as inputs. trisb=0; // set portb pins as output. portb=0; // set portb pins to low. duration=250; // set initial value of delay at 250ms while(1) // infinite loop. { if(button2) // if button2 is pressed, execute { // the following statements. duration+=10; // increment duration by 10ms. if(duration==1000) // if duration equals 1000ms, { duration=990; // make it 990ms. } // this will limit the max delay. } if(button3) // if button3 is pressed, execute { // the following statements. duration-=10; // reduce delay by 10ms. if(duration==10) // if delay equals 10ms, { duration=20; // make it 20ms. } // this will limit the min delay. } if(button1==0) // if button1 pin is not pressed, { // execute the statements below check1(); // call routine check1. portb <<= 1; // shift bits in portb to its left, ones. delay_ms(duration); // pause for the value of duration. } else // else if porta.0 pin is high { // execute the statements below. check2(); // call routine check2. portb>>=1; // shift bits in portb to its right by one place. delay_ms(duration); // pause for the value of duration. } } } void check1(void) // check1 routine. { if(portb==0) // if portb equals zero, { // then execute the statements below. portb=1; // make portb to display 1. delay_ms(duration); // pause for the value of duration. } } void check2(void) // check2 routine. { if(portb==0) // if portb equals zero, { // then execute the following statements. portb=128; // make portb to display 128. delay_ms(duration); // pause for the value of duration. } } /* Lets try to understand the C program line by line. In the beginning of the program you can see two routines check1 & check2. These routines get called from the main routine void main(void). In Basic programming we call it sub-routines. Unlike the Basic sub-routine it does not have a return statement.It is important that you declare all the routines used at the beginning of the code for the compiler to recognize it latter in the program. The routine check1 checks if portb value is zero and if found true makes it equal to one, so that the binay progression can repeatedly continue. Similarly check2 checks if portb valve is zero and if true makes it equal to 128, so that the binary regression can continue. See that check2 rou- tine is called only if button1 is pressed or true. Next in line is int duration; statement. See that duration is declared as an integer because we require more than one byte to store a duration of 1000. Also you can see that it is declared outside the all the routines, meaning that all routines can access the variable and modify it. Thats why we call it global variable. The next statement is #define button1 porta.0. What the compiler does is, it simply replaces button1 with porta.0 while compiling. For us its more convenient and easy to understand the code.So the name button1 is an alais for porta.0. The rest of the program is self explanatory.In the main routine trisa=7; sets porta pins 0-2 as input. trisb=0 makes all pins in portb as output. The delay variable is given an initial value of 250ms. Then the program enters the endless loop, while(1);. In this loop we check if the buttons are pressed. The if statement if(button2) is same as if(button2==1). It means if button2 is true or 1 execute the statements that follows. One other new operator we have used is portb>>=0; and portb<<=0;. They are shift right & assign and shift left and assign operators. They create the same effect as b0*=2; and b0/=2; used in our earlier program. This program compiles to 98 words. */ PIC8modified.bmp
  24. /* BINARY PROGRESSION The binary progression program lights each LED in sequence, starting from the first LED connected to RB0, then the second led(RB1) while the first is switched off and then the third led connected to RB2 is switched on while the second led is switched off and so on. So the LEDs will scroll from left to right. Before you load the hex file onto your chip, you can use the built in simulator on the SourceBoost IDE to check if your code is working just as intended. Read the IDE user's manual to get help to configure your plugins. Connections: pin4- MCLR pin to +5v via 4.7K resistor pin15-16 4mhz crystal(across pin 15 & 16) connect 22pf capacitors( between pin15 & gnd, pin16 & gnd) pin6-RB0-connect LED to pin6 via 470 ohms. Cathode of LED to gnd. pin7-RB1-connect LED to pin7 via 470 ohms. Cathode of LED to gnd. pin8-RB2-connect LED to pin8 via 470 ohms. Cathode of LED to gnd. pin9-RB3-connect LED to pin9 via 470 ohms. Cathode of LED to gnd. pin10-RB4-connect LED to pin10 via 470 ohms. Cathode of LED to gnd. pin11-RB5-connect LED to pin11 via 470 ohms. Cathode of LED to gnd. pin12-RB6-connect LED to pin12 via 470 ohms. Cathode of LED to gnd. pin13-RB7-connect LED to pin13 via 470 ohms. Cathode of LED to gnd. */ #include <system.h> #pragma CLOCK_FREQ 4000000 // config clock to 4mhz. // Set configuration fuse #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF void main() { trisb=0; // make portb pins as output char b0; // declare b0 as character char b1; // declare b1 as character while(1) // endless loop { b0=1; // initialize b0 variable to 1. portb=b0; // display b0 value on portb delay_ms(250); // pause 0.5s for us to see the lit LED delay_ms(250); for(b1=0;b1<7;b1++) // for loop for seven times { b0*=2; // C syntax for multiply and assign. portb=b0; // similar to basic syntax of b0=b0*2 delay_ms(250); // pause 0.5 sec to see the LED on. delay_ms(250); } } } /* The only statement new in this C program is " b0*=2;". Here the C compiler multiplies b0 value with 2 and assigns this new value to b0. It is similar to b0=b0*2. Multiplying b0 with 2, causes the bits in b0 to shift left by one place. Take a print of BoostC compiler reference manual and you will find the list of arithmatic operators, assignment operator, comparison operator, logical operators. This program compiles to 43 words. In the above code change b0=1; as b0=128; in the while loop and also change b0 *= 2; as b0 /= 2; in the for loop. Build the code and check it on the simulator. What do you see? You can see the LED patern has reversed, ie. the LEDs would scroll from left to right. You could call it regression. If you wish to store it, use the save as option first and then build it using the quick buid option in the project menu of the tool bar. */
  25. Hi guys, I was just testing the code for my thread " pic micro programming in BoostC for beginners ", using the simulator. I am using the porta pins to read buttons and dynamically change the delay time. portb is used as output connected to LEDs. The LEDs are made to scroll from left to right or right to left based on the position of switch in porta.0 Now the question. When i run it on the simulator, the vaiable watch increments or decrements the duration variable correctly but the LEDs in the LED block suddenly moves fast or slow not commensurate with the delay(duration) variable. Some time it works fine? Can any one say why? See code below. #include <system.h> #pragma CLOCK_FREQ 4000000 // Set configuration fuse #pragma DATA _CONFIG, _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF void check1(void); void check2(void); int duration; // duration is declared as global variable #define button1 porta.0 // button1 is alais for porta.0 #define button2 porta.1 // button2 is alais for porta.1 #define button3 porta.2 // button3 is alais for porta.2 void main(void) { trisa=7; // set porta pin0-pin3 as inputs. trisb=0; // set portb pins as output. portb=0; // set portb pins to low. duration=250; while(1) // infinite loop. { if(button2) // if button2 is pressed, execute { // the following statements. duration+=10; // increment duration by 10ms. if(duration==1000) // if duration equals 1000ms, { duration=990; // make it 990ms. } } if(button3) // if button3 is pressed, execute { // the following statements. duration-=10; // reduce delay by 10ms. if(duration==10) // if delay equals 10ms, { duration=20; // make it 20ms. } } if(button1==0) // if button1 pin is not pressed, { // execute the statements below check1(); // call routine check1. portb <<= 1; // shift bits in portb to its left, ones. delay_ms(duration); // pause for 0.5 seconds. } else // else if porta.0 pin is high { // execute the statements below. check2(); // call routine check2. portb>>=1; // shift bits in portb to its right by one place. delay_ms(duration); // pause 0.5 seconds. } } } void check1(void) // check1 routine. { if(portb==0) // if portb equals zero, { // then execute the statements below. portb=1; // make portb to display 1. delay_ms(duration); // pause 0.5 seconds. } } void check2(void) // check2 routine. { if(portb==0) // if portb equals zero, { // then execute the following statements. portb=128; // make portb to display 128. delay_ms(duration); // pause 0.5 seconds. } } Raghunathan
×
×
  • Create New...