View previous topic :: View next topic |
Author |
Message |
ounvme
Joined: 21 Apr 2012 Posts: 13
|
Basics Working - PIC18 ADC/PWM |
Posted: Sat Apr 21, 2012 4:31 pm |
|
|
To start off I am about as green as a beginner can get. I don't know C very well, I don't know assembly, and I have never used uC's. I however am pretty proficient at building circuits and learning from others coding examples.
I am using a PIC18F26K80 with MPLAB v8.84 and CCS PIC C DEMO 4.13 & PICkit 3
The goal: To blink an LED
I started by using the wizard and the supplied example but I cannot get the LED to power on let alone blink.
Circuit Setup:
uC(Pin) PICkit 3
VDD(20) +5V/Pin2
VSS(19) GND/Pin3
VSS(08) GND
MCLR(1) Pin1 R10k->VDD
PGD(28) Pin4
PGC(27) Pin5
RC4(15) LED+ -> R220 ->GND
Code: |
#include <18F26K80.h>
#device adc=16
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOBROWNOUT //No brownout reset
#FUSES WDT_NOSLEEP //Watch Dog Timer, disabled during SLEEP
#use delay(int=4000000)
#define LED PIN_C4
#define DELAY 1000
#include <LED FLASH2.h>
void main()
{
setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
setup_timer_4(T4_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
setup_oscillator(OSC_4MHZ|OSC_NORMAL|OSC_31250|OSC_PLL_OFF);
//Example blinking LED program
while(true)
{
output_low(LED);
delay_ms(DELAY);
output_high(LED);
delay_ms(DELAY);
}
}
|
The code compiles in PIC C and also in the MPLAB project with no errors.
The code is loaded to the pic with the PICkit and verified however the LED doesn't blink light flash or anything. Help Please
Last edited by ounvme on Mon Jun 04, 2012 5:02 pm; edited 2 times in total |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Apr 21, 2012 5:48 pm |
|
|
Try a more simple program. I'm not at a location where I can test this in
hardware, but you need to start with a simple program:
Code: |
#include <18F26K80.h>
#fuses INTRC_IO,NOWDT,PUT,BROWNOUT
#use delay(clock=4M)
//======================================
void main(void)
{
while(1)
{
output_high(PIN_B0);
delay_ms(500);
output_low(PIN_B0);
delay_ms(500);
}
} |
|
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Sun Apr 22, 2012 10:36 am |
|
|
The simple program worked and I was able to go step by step in debug mode. I figured the problem to be the fuses that I was using. So now I have both programs running in debug mode. When I unplug the programmer and apply power I get nothing. I assume I am missing a fuse or something in the circuit. Does it have to do with the MCLR pin? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Sun Apr 22, 2012 10:43 am |
|
|
You'll have to change from 'debug' to 'release' and then recompile/download code into PIC. |
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Sun Apr 22, 2012 5:31 pm |
|
|
Awesome I can work in debug and external power mode. I am going to have to read more about how the fuses work as those seem to be very important.
The next step is to learn the hardware A/D and see if I can change the blinking speed with a pot.
The device I am using has 8 12bit a/d. For my application 8 or 10 bit would work fine. Can I use the internal a/d at a lower resolution?
I would like to use AN0 internally referenced to VDD. The data sheet states that for 12bit I need 14Tad what about 10 and 8 bit? |
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Mon Apr 23, 2012 9:03 pm |
|
|
Can someone "dumb" down the setting of adcon2?
To begin I won't be using an interrupt until I learn more about those also.
What I have so far from the data sheet
Code: |
ADCON0 = 0b00000000
7=0 UNUSED
6-2=00000 AN0
1=0 NOT IN PROGRESS
0=0 OFF
ADCON1 = 0b00000001
7=0
6=0 ECCP1?? WHAT IS THIS?
5-4=00 VREF+ =VDD
3=0 VREF- =VSS
2-0=001 AN0
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Tue Apr 24, 2012 7:47 am |
|
|
Thanks PCM. I will look more into that after I understand how the A/D timing functions and how to properly configure the ADCON2 register. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 24, 2012 11:15 am |
|
|
This post has an example of using the ADC on the "K80" series PICs:
http://www.ccsinfo.com/forum/viewtopic.php?t=46255&start=5
The ADC clock divisor shown in that code is for the PIC running at 4 MHz.
If you use a different PIC oscillator frequency, then look in the ADC
section of the 18F26K80 data sheet and find the table that gives the
correct divisor to use. Then look in the 18F26K80.h file, in the ADC
section, and see what constant to use with the setup_adc() function to
select that divisor value. |
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Wed Apr 25, 2012 11:03 pm |
|
|
The 18F26K80 uses 12 bit and the registers are setup much differently. It is a good reference but still does not make it clear for how I would calculate TAD and Tacq for my application. With the ADCON0 the data sheet does not specify how to configure more then one input as analog. But uses ANCON0 to specify port settings. How does this work if ADCON0 only configures 1 pin?
What I am trying to achieve. 3 A/D pins with VSS/VDD reference using a 1Kohm pot(DC circuit max impedance 2.5Kohm according to the data sheet) with 12bit resolution.
Its seems as the data sheet over complicates how to configure this or I am just not capable of understanding what it is trying to say. It is frustrating non the less.
From the Data Sheet: Where is the 2048 coming from? Could that be 10bit*2?
TACQ = Amplifier Settling Time + Holding Capacitor Charging Time + Temperature Coefficient
= TAMP + TC + TCOFF
VHOLD = (VREF – (VREF/2048)) • (1 – e(-TC/CHOLD(RIC + RSS + RS)))
or
TC = -(CHOLD)(RIC + RSS + RS) ln(1/2048)
TACQ = TAMP + TC + TCOFF
TAMP = 0.2 s
TCOFF = (Temp – 25C)(0.02 s/C)
(85C – 25C)(0.02 s/C)
1.2 s
Temperature coefficient is only required for temperatures > 25C. Below 25C, TCOFF = 0 ms.
TC = -(CHOLD)(RIC + RSS + RS) ln(1/2048) s
-(25 pF) (1 k + 2 k + 2.5 k) ln(0.0004883) s
1.05 s
TACQ = 0.2 s + 1.05 s + 1.2 s
2.45 s |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Apr 25, 2012 11:31 pm |
|
|
Quote: |
The 18F26K80 uses 12 bit and the registers are setup much differently.
|
The 18F46K80 in the example I linked to, is in the same PIC family
as the 18F26K80. They both have 12-bit A/D's. It's not setup differently.
In my linked example, I tell the compiler to return a 12-bit right-justified
result by this statement:
Quote: |
does not specify how to configure more then one input as analog
|
The ADC section of the 18F26K80.h file tells you exactly how to select
multiple A/D channels. See the following file:
c:\program files\picc\devices\18f26k80.h
Quote: |
What I am trying to achieve. 3 A/D pins with VSS/VDD reference using a
1Kohm pot(DC circuit max impedance 2.5Kohm according to the data
sheet) with 12bit resolution.
|
Try the example code that I posted. Get it running for one channel, then
add the other channels. |
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Sun May 27, 2012 10:39 pm |
|
|
Well I have had some free time to play with some examples and do some testing. I am having an issue with A/D above 8 bit. Using 8 bit I can adjust a potentiometer and change the blink rate of the led. Anything else and the behavior is eratic. Why is this?
Code: |
#include <18F26K80.h>
#device adc=10
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOBROWNOUT //No brownout reset
#FUSES WDT_NOSLEEP //Watch Dog Timer, disabled during SLEEP
#use delay(int=4000000)
#define LED PIN_C4
void main()
{
int temp;
setup_adc_ports(sAN0);
setup_adc(ADC_CLOCK_DIV_4|ADC_TAD_MUL_2);
setup_timer_2(T2_DIV_BY_16,155,1); //2.4 ms overflow, 2.4 ms interrupt
setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
setup_timer_4(T4_DISABLED,0,1);
setup_ccp2(CCP_PWM);
set_pwm2_duty((int16)20);
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
while(true)
{
set_adc_channel(0);// AN0 reading
delay_us(20);// 20us delay
temp=read_adc(); // AN0 reading: 0<=temp<=255
output_high(LED);
delay_ms(temp);
output_low(LED);
delay_ms(temp);
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19505
|
|
Posted: Mon May 28, 2012 1:19 am |
|
|
A very old one.
What can an 'int' hold in CCS?. Not a 10bit, or 12bit value.....
This is why I like to use int8, and int16 types. This way the code 'shows' the size of the selected type.
Best Wishes |
|
|
ounvme
Joined: 21 Apr 2012 Posts: 13
|
|
Posted: Mon May 28, 2012 8:07 pm |
|
|
That seems to have fixed the error. I tried int10 and 12 but not int16. For what I am using the 8 bit adc is more than enough. I wanted to test with 10 12 and 16. Here is the beginning of my work in progress. So far adjusting a 1k pot will change the blink rate and PWM. The 0-255 is scaled by a multiplier to adjust the duty cycle from 0-100. This may not be the correct way to handle this but so far it works. The next phase will be to add in the other 2 hardware A/D and PWM. After I get the whole thing working I will start to look into using making the code more efficient.
Please discuss my logic.
Read ADC
Set initial PWM
Check for change in ADC1,2,3
Loop
Adjust PWM if ADC
I am a big fan of using sub routines. It was the way I learned basic programming and it delivers code that is very easy to follow. If anyone can give me a 30 second crash course on calling subs and passing variables that would be great.
Here is the latest working code
Code: |
#include <18F26K80.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES WDT128 //Watch Dog Timer uses 1:128 Postscale
#FUSES NOXINST //Extended set extension and Indexed Addressing mode disabled (Legacy mode)
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOBROWNOUT //No brownout reset
#FUSES WDT_NOSLEEP //Watch Dog Timer, disabled during SLEEP
#use delay(int=4000000)
#define LED PIN_C4
#define DELAY 1000
void main()
{
int8 pwm2;
int16 temp;
int8 pwm1;
setup_adc_ports(sAN0);
setup_adc(ADC_CLOCK_DIV_4|ADC_TAD_MUL_2);
setup_timer_2(T2_DIV_BY_16,155,1); //2.4 ms overflow, 2.4 ms interrupt
setup_timer_3(T3_DISABLED | T3_DIV_BY_1);
setup_timer_4(T4_DISABLED,0,1);
setup_ccp2(CCP_PWM);
set_pwm2_duty((int16)20);
setup_comparator(NC_NC_NC_NC);// This device COMP currently not supported by the PICWizard
//Example blinking LED program
while(true)
{
set_adc_channel(0);// AN0 reading
delay_us(20);// 20us delay
temp=read_adc(); // AN0 reading: 0<=temp<=255
pwm1=temp/2.44;
set_pwm2_duty(pwm1);
output_high(LED);
delay_ms(temp);
output_low(LED);
delay_ms(temp);
}
}
|
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Tue May 29, 2012 12:11 am |
|
|
Quote: | If anyone can give me a 30 second crash course on calling subs and passing variables that would be great. | First reaction is that you should get yourself a book on C as you are now asking our time for something that is easy to look up yourself.
Here a quick hint though:
In Basic there is a difference between calling a subroutine and a function. In C there is no such difference. When writing a function you can specify it to return a value or not.
Also: in Basic the goto command is often used. In C it is considered bad practice to use 'goto' it results into spaghetti code. It can always be replaced by other constructs like if-then-else, for-loops, switch cases and do-while. |
|
|
|