void main(int argc, char** argv)
I am a little surprised a compiler does that (bolded) for setting a port bit in the 16F/18F series.
...
...
I am less sure about using IORWF since that is a byte operation, but I could not find a definitive statement, i.e., from Microchip, saying it was safe.
...
Edit#2: Here is a PicList link that states andwf, iorwf, and xorwf are not "safe" from r-m-w (as suspected). Since no one challenged it, I assume it is accurate:
I'm listing few observations about your code.
- You should be able to use simple "void main(void)" instead of "void main(int argc, char** argv)".
- You are not calling the "IntADC()" -function properly.. the line "IntADC;" does nothing.
- It would be better style not to omit braces {}. Makes the code easier to read and prevents future bugs (you might add more lines and forget to add the braces).
- Learn to write macros.. makes writing code easier and results in more readable and flexible code..and prevents bugs. Just don't go crazy with macros.
I generally like your style. You could separate the ADC conversion to a function like "int read_adc();" which starts ADC conversion, waits it to finish and returns the value.
...
(SetupClock());
(IntADC());
...
Is it possible to write to two different bytes of a 16 bit word? ie, byte 1 and byte 2 of the 16 bit variable.
#include <p18cxxx.h>
#include <timers.h>
/********************************************************************
* Function Name: ReadTimer1 *
* Return Value: char: Timer1 16-bit value *
* Parameters: void *
* Description: This routine reads the 16-bit value from *
* Timer1. *
********************************************************************/
unsigned int ReadTimer1(void)
{
union Timers timer;
timer.bt[0] = TMR1L; // Read Lower byte
timer.bt[1] = TMR1H; // Read upper byte
return (timer.lt); // Return the 16-bit value
}
/******************************************************************************
// * TIMERS PERIPHERAL LIBRARY HEADER FILE
******************************************************************************
* FileName: timers.h
* Dependencies: See include below
* Processor: PIC18
* Compiler: MCC18
* Company: Microchip Technology, Inc.
...
*****************************************************************************/
#include <pconfig.h>
/* PIC18 timers peripheral library. */
/* used to hold 16-bit timer value */
union Timers
{
unsigned int lt;
char bt[2];
};
... In the PIC's, writing to a port with bsf or bcf, as your MikroeC apparently does, ...
... your claim that the MikroeC compiler uses the BSF instruction ...
... (if it is really done that way) ...
...
// compiled for PIC 12F675 using MikroC v8;
void main ()
{
CMCON = 0b00000111; // comparators OFF
GPIO.F2 = 1;
}
// result;
$0000 $2804 GOTO _main
$0004 $ _main:
;blah.c,19 :: void main ()
;blah.c,23 :: CMCON = 0b00000111; // comparators OFF
$0004 $3007 MOVLW 7
$0005 $1303 BCF STATUS, RP1
$0006 $1283 BCF STATUS, RP0
$0007 $0099 MOVWF CMCON
;blah.c,26 :: GPIO.F2 = 1;
$0008 $1505 BSF GPIO, 2
;blah.c,30 :: }
$0009 $2809 GOTO $
---------------------------------------------------
// compiled for PIC 18F1320 using MikroC v8;
void main ()
{
TRISA = 0b00010000;
LATA.F2 = 1;
}
// result;
$0000 $EF04 F000 GOTO _main
$0008 $ _main:
;blah.c,1 :: void main ()
;blah.c,3 :: TRISA = 0b00010000;
$0008 $0E10 MOVLW 16
$000A $6E92 MOVWF TRISA, 0
;blah.c,4 :: LATA.F2 = 1;
$000C $8489 BSF LATA, 2, 0
;blah.c,5 :: }
$000E $D7FF BRA $
---------------------------------------------------
// compiled for PIC 12F675 using MikroC PRO v4.15;
void main ()
{
CMCON = 0b00000111; // comparators OFF
GPIO.F2 = 1;
}
// result;
;blah.c,1 :: void main ()
;blah.c,3 :: CMCON = 0b00000111; // comparators OFF
MOVLW 7
MOVWF CMCON+0
;blah.c,4 :: GPIO.F2 = 1;
BSF GPIO+0, 2
;blah.c,5 :: }
GOTO $+0
---------------------------------------------------
// compiled for PIC 18F1320 using MikroC PRO v4.15;
void main ()
{
TRISA = 0b00010000;
LATA.F2 = 1;
}
// result;
;blah.c,1 :: void main ()
;blah.c,3 :: TRISA = 0b00010000;
MOVLW 16
MOVWF TRISA+0
;blah.c,4 :: LATA.F2 = 1;
BSF LATA+0, 2
;blah.c,5 :: }
GOTO $+0
I find all this talk about RMW on mid range PIC's academic.... There is a work round and I would assume most of the compilers out there use it.
Source=Microchip
To avoid this with PIC16 devices, you never bsf/bcf a port, you simply read the port, write it to another register, modify that register, then read that register and write it back to the port. This is known as "shaddowing". The PIC18 is easier, since instead of needing to do that, you write to the LATx register directly, thus skipping the read step in hardware.
Source=Mr RB
MikroC is probably the best on the market re PIC 16F/18F and has extremely comprehensive library functions ready to go for just about any peripheral. It also accepts bit manipulation and defines, which compile to good assembler, so
PORTB.F5 = 1;
assembles to a single instruction;
BSF PORTB,5
beware of lesser compilers that will compile a single bit set instruction to slower/fatter/worse assembler like;
MOVLW (mask)
IORWF PORTB
Search Pages
16F628 278
16F877 188
16F84 298
RMW >300
16F1519 <1 (6 posts total)
...
That is why I expressed surprise that the "best" compiler* didn't use one of the available work arounds (e.g., a mask and movwf, or a delay) and didn't follow the unambiguous instruction of the chip manufacturer.
...
Perhaps, the real purpose of the extra steps in the "lesser" compilers we are warned about is to introduce a delay as you (Ian) suggest.
...
I have written MikroElektronika to gets its response as to setting bits in a port.
...
Source=Microchip
To avoid this with PIC16 devices, you never bsf/bcf a port, you simply read the port, write it to another register, modify that register, then read that register and write it back to the port. This is known as "shaddowing". ...
Source=Microchip
To avoid this with PIC16 devices, you never bsf/bcf a port, you simply read the port, write it to another register, modify that register, then read that register and write it back to the port. This is known as "shaddowing". The PIC18 is easier, since instead of needing to do that, you write to the LATx register directly, thus skipping the read step in hardware.
Well this stranded far away from C programming.. I would like to talk about C programming.
There are about 10 was to do it but it's common to use the union method:
https://www.tutorialspoint.com/cprogramming/c_unions.htm
timer.lt is the 16 bit value
timer.bt[0] is the lower 8 bit value of timer.lt
timer.bt[1] is the upper 8 bit value of timer.lt
/*
* File: newmain1.c
* Author: chris
*
* Created on August 19, 2013, 6:11 PM
*/
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <htc.h>
#define _XTAL_FREQ 8000000
#define RA5 (PORTAbits.RA5)
#pragma config FOSC = INTOSC, CLKOUTEN = OFF, PLLEN = OFF, WDTE = OFF, LVP = OFF, MCLRE = ON
void SetupClock (void) //set up clock
{
OSCCON = 0b01110010;
}
void IntADC (void) //setup ADC
{
//** Initalise Ports FOR ADC **//
//PORTA = 0x00;
TRISA = 0b00001111; //RA4,RA5 outputs, RA0, RA1 Inputs
//** Set Up ADC Parameters **//
ANSELA = 0b00000111; //RA4 Output, RA5 Output, all others input
ADRESH = 0x00; //Set the analog high bits to 0
ADRESL = 0x00;
ADCON1 = 0b10010000; // Sets ADRESL to contain the first 7 bits of conversion, ADRESH will have the final 3 bits.
} // void InitADC(void)
int main (){
SetupClock();
IntADC();
unsigned int ADCresult;
ADCresult = 0;
ADCON0bits.ADON = 1; //Turns on ADC module
ADCON0bits.CHS = 2; //AN0 as input
while (1)
{
ADCON0bits.GO = 1; //Starts Conversion
__delay_us(35);
while (ADCON0bits.GO_nDONE); //wait till ADC conversion is over
{
ADCresult = (ADRESH <<8 | ADRESL) ;
if (ADCresult > 0b1000000000)
RA5 = 1;
else
RA5 = 0;
return ADCresult; //THIS is important. Function doesnt seem to work without it.
//also removed the continue statement.
}
}
}
The reason it wants a return is because you have declared main to return an int. Change it to void main() and it should be happy.
BTW, returning from main is not a good idea as it has nowhere to go except to crash.
Mike.
/*
* File: ADC_Ver1
* Author: chris
* This is Basic ADC Code for the PIC12F1840 Series. Should be portable to others
* Created on August 19, 2013, 6:11 PM
*/
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <htc.h>
#define _XTAL_FREQ 8000000
#define RA5 (PORTAbits.RA5)
#pragma config FOSC = INTOSC, CLKOUTEN = OFF, PLLEN = OFF, WDTE = OFF, LVP = OFF, MCLRE = ON
void SetupClock (void) //set up clock
{
OSCCON = 0b01110010;
}
void IntADC (void) //setup ADC
{
//** Initalise Ports FOR ADC **//
//PORTA = 0x00;
TRISA = 0b00001111; //RA4,RA5 outputs, RA0, RA1 Inputs
//** Set Up ADC Parameters **//
ANSELA = 0b00000111; //RA4 Output, RA5 Output, all others input
ADRESH = 0x00; //Set the analog high bits to 0
ADRESL = 0x00;
ADCON1 = 0b10010000; // Sets ADRESL to contain the first 7 bits of conversion, ADRESH will have the final 3 bits.
} // void InitADC(void)
void main ()
{
SetupClock();
IntADC();
unsigned int ADCresult; //ADCresult for Channel x
ADCresult = 0;
ADCON0bits.ADON = 1; //Turns on ADC module
ADCON0bits.CHS = 2; //AN2 as input
ADCON0bits.GO = 1; //Starts Conversion
__delay_us(35); //small delay to get value
while (ADCON0bits.GO_nDONE); //wait till ADC conversion is over
{
ADCresult = (ADRESH <<8 | ADRESL) ;
if (ADCresult > 768)
RA5 = 1;
else
RA5 = 0;
}
}
/*
* File: Battery Charger Controller
* Author: chris
* Checks if the Battery is equal to, or greater than the charge voltage, then turns off a PFET
* and turns on a "done" led. But for now, turns on a LED when values >512
* Created on August 27, 2013, 6:11 PM
*/
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <htc.h>
#define _XTAL_FREQ 8000000
#define RA5 (PORTAbits.RA5) //Charge LED
#define RA4 (PORTAbits.RA4) // PFET
#pragma config FOSC = INTOSC, CLKOUTEN = OFF, PLLEN = OFF, WDTE = OFF, LVP = OFF, MCLRE = ON
void SetupClock (void) //set up clock
{
OSCCON = 0b01110010;
}
void IntADC (void) //setup ADC
{
//** Initalise Ports FOR ADC **//
//PORTA = 0x00;
TRISA = 0b00001111; //RA4,RA5 outputs, RA0, RA1 Inputs
//** Set Up ADC Parameters **//
ANSELA = 0b00000111; //RA4 Output, RA5 Output, all others input
ADRESH = 0x00; //Set the analog high bits to 0
ADRESL = 0x00;
ADCON1 = 0b10010000; // Sets ADRESL to contain the first 7 bits of conversion, ADRESH will have the final 3 bits.
ADCON0bits.ADON = 1;
} // void InitADC(void)
void main (){
SetupClock();
IntADC();
unsigned int Vcharge; //ADCresult for Channel x
unsigned int Vcurrent;
unsigned int Vbattery;
Vcharge, Vcurrent, Vbattery = 0;
ADCON0bits.CHS = 2; //AN2 as input
__delay_ms (10);
ADCON0bits.GO = 1;
//__delay_ms (10); //small delay to get value
while (ADCON0bits.GO_nDONE); //wait till ADC conversion is over
{
Vcharge = (ADRESH <<8 | ADRESL) ;
}
__delay_ms (100);
IntADC();
ADCON0bits.CHS = 0;
__delay_ms (10);
ADCON0bits.GO = 1;
// __delay_ms (10);
while (ADCON0bits.GO_nDONE);
{
Vcurrent = (ADRESH <<8 | ADRESL);
}
//Vbattery = Vcharge - Vcurrent;
if (Vcharge >512)
{
RA4 = 1;
}
else
RA4 = 0;
if (Vcurrent > 512 )
{
RA5 = 1;
}
else
RA5 = 0;
}
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?