Some Anon Guy
Junior Member
Offline
Posts: 43
Thank You
-Given: 58
-Receive: 25
|
|
« on: September 05, 2013, 06:08:30 18:08 » |
|
Here I will compile a list of some code examples for beginners. (as I figure out/learn interesting things that I think could help others) These are in no way always the most efficient way of doing things, just they way I figured it out and wanted to share to help other beginners...
This is a simple function that will check whether a bit is a 1 or a 0 in a variable. Pass it the variable and the bit position you want to check (0-7 0 being the LSB) it will return 1 if set, or 0 if not...
int CHECK_BIT(int _var, int _pos){ _var&=1<<_pos; if (_var !=0){ return (1); } else{ return (0); } }
|
|
« Last Edit: September 05, 2013, 06:12:12 18:12 by Some Anon Guy »
|
Logged
|
|
|
|
pablo2048
Active Member
Offline
Posts: 113
Thank You
-Given: 136
-Receive: 86
|
|
« Reply #1 on: September 05, 2013, 06:29:59 18:29 » |
|
Same function: int CHECK_BIT(int _var, int _pos) {
return (_var & (1 << _pos))? 1:0; }
|
|
|
Logged
|
|
|
|
Some Anon Guy
Junior Member
Offline
Posts: 43
Thank You
-Given: 58
-Receive: 25
|
|
« Reply #2 on: September 06, 2013, 03:11:55 15:11 » |
|
Here are 2 functions to read and write to an I2C EEProm with a 16Bit Data Address and 8Bit Data location. It was written with MikroC Pro for Pic char I2CEERE(char _devAdd, int _dataAdd){ // _devAdd is the 7bit device address // The 8th bit is the Read/Write bit (RW). // This bit is set to 1 for Read and 0 for Write operations. char _return; char _dataAddHI, _dataAddLO; char _devWR = _devAdd << 1; char _devRE = _devAdd << 1 |0x01; _dataAddHI = _dataAdd >> 8; _dataAddLO = _dataAdd & 0x00FF; I2C1_Start(); // issue I2C start signal I2C1_Wr(_devWR); // send device address + Write bit I2C1_Wr(_dataAddHI); // send HIGH data address byte I2C1_Wr(_dataAddLO); // send LOW data address byte I2C1_Repeated_Start(); // issue I2C repeated start I2C1_Wr(_devRE); // send device address + Read bit _return = I2C1_Rd(0); // Read the data (NO acknowledge) I2C1_Stop(); // issue I2C stop return _return; }
void I2CEEWR(char _data, char _devAdd, int _dataAdd){ // _devAdd is the 7bit device address // The 8th bit is the Read/Write bit (RW). // This bit is set to 1 for Read and 0 for Write operations. char _dataAddHI, _dataAddLO; char _devWR = _devAdd << 1 |0x01; _dataAddHI = _dataAdd >> 8; _dataAddLO = _dataAdd & 0x00FF; I2C1_Start(); // issue I2C start signal I2C1_Wr(_devWR); // send device address + Write bit I2C1_Wr(_dataAddHI); // send HIGH data address byte I2C1_Wr(_dataAddLO); // send LOW data address byte I2C1_Wr(_data); // send data (data to be written to EEprom) I2C1_Stop(); // issue I2C stop signal }
|
|
|
Logged
|
|
|
|
pablo2048
Active Member
Offline
Posts: 113
Thank You
-Given: 136
-Receive: 86
|
|
« Reply #3 on: September 06, 2013, 04:25:11 16:25 » |
|
I think, this can be more readable: (only I2CEERE, same way in WR method) uint8_t I2CEERE(uint8_t _devAdd, uint16_t _dataAdd){ // _devAdd is the 7bit device address // The 8th bit is the Read/Write bit (RW). // This bit is set to 1 for Read and 0 for Write operations.
uint8_t _return; uint8_t _devWR = _devAdd << 1;
I2C1_Start(); // issue I2C start signal I2C1_Wr(_devWR); // send device address + Write bit I2C1_Wr(_dataAdd >> 8); // send HIGH data address byte I2C1_Wr((uint8_t) _dataAdd);// send LOW data address byte I2C1_Repeated_Start(); // issue I2C repeated start I2C1_Wr(_devWR | 0x01); // send device address + Read bit _return = I2C1_Rd(0); // Read the data (NO acknowledge) I2C1_Stop(); // issue I2C stop return _return; }
there is no need to compute both addresses and MSB & LSB bytes... Save the RAM memory even if it's local (aka stack) variable or register...
|
|
|
Logged
|
|
|
|
hate
Hero Member
Offline
Posts: 555
Thank You
-Given: 156
-Receive: 355
|
|
« Reply #4 on: September 06, 2013, 04:33:05 16:33 » |
|
In the case where the bit checking result will be treated as 'bool', it can be accomplished by a macro too. This will also be faster and compile into 1 or 2 native assembly instruction in most architectures. #define btest(_var, _pos) (_var& (1<< _pos)) One should remember that 'define's are not type-safe in general.
|
|
|
Logged
|
Regards...
|
|
|
pablo2048
Active Member
Offline
Posts: 113
Thank You
-Given: 136
-Receive: 86
|
|
« Reply #5 on: September 06, 2013, 05:07:31 17:07 » |
|
In the case where the bit checking result will be treated as 'bool', it can be accomplished by a macro too. This will also be faster and compile into 1 or 2 native assembly instruction in most architectures. #define btest(_var, _pos) (_var& (1<< _pos)) One should remember that 'define's are not type-safe in general. Indeed, but he wants (int) 0/1 output...
|
|
|
Logged
|
|
|
|
Make_Pic
Junior Member
Offline
Posts: 55
Thank You
-Given: 3
-Receive: 9
|
|
« Reply #6 on: September 21, 2013, 02:06:25 02:06 » |
|
Hi all Why do you use an underline before a variable? For example: _var Where can I read about it?
regards
|
|
|
Logged
|
|
|
|
Brosske
Active Member
Offline
Posts: 105
Thank You
-Given: 75
-Receive: 292
|
|
« Reply #7 on: September 21, 2013, 07:16:35 07:16 » |
|
Hi all,
The underscore is simply a convention; nothing more. As such, its use is always somewhat different to each person. Here's how I understand them : an underscore usually indicates a private member (or local) variable.
greetz
|
|
|
Logged
|
Do or do not - there is no try
|
|
|
hate
Hero Member
Offline
Posts: 555
Thank You
-Given: 156
-Receive: 355
|
|
« Reply #8 on: September 21, 2013, 01:52:18 13:52 » |
|
Preceding underscore(s) is/are usually used by compiler/system specific defines which are not to be modified by the inexperienced and the following underscore(s) is/are usually appended to member variables in C++. But it's a matter of convention really as Brosske said. They can be freely used unless one doesn't interfere with a critical variable/definition.
|
|
|
Logged
|
Regards...
|
|
|
odessa
Newbie
Offline
Posts: 22
Thank You
-Given: 101
-Receive: 16
|
|
« Reply #9 on: September 21, 2013, 11:40:37 23:40 » |
|
Heres a full set of bitwise routines I use : #define bitSet(var,bitno) (var|=1<<bitno) #define bitClr(var,bitno) (var&=~(1<<bitno)) #define bitTest(var, bitno) ((var) & (1 << (bitno))) #define bitToggle(var,bitno) ((var&(1<<bitno))!=0) ? (var &= ~(1<<bitno)) : (var |= (1<<bitno))
Hope they help someone
|
|
|
Logged
|
|
|
|
hate
Hero Member
Offline
Posts: 555
Thank You
-Given: 156
-Receive: 355
|
|
« Reply #10 on: September 22, 2013, 11:16:05 11:16 » |
|
Heres a full set of bitwise routines I use : #define bitToggle(var,bitno) ((var&(1<<bitno))!=0) ? (var &= ~(1<<bitno)) : (var |= (1<<bitno))
A better and much faster bit toggle is #define bitToggle(var, bitno) (var^= (1<<bitno))
|
|
|
Logged
|
Regards...
|
|
|
odessa
Newbie
Offline
Posts: 22
Thank You
-Given: 101
-Receive: 16
|
|
« Reply #11 on: September 23, 2013, 09:53:10 09:53 » |
|
Hi Hate, I tried that but it doesn't work ... edit: well not in C18, does in HiTEch C ...
|
|
« Last Edit: September 23, 2013, 09:59:33 09:59 by odessa »
|
Logged
|
|
|
|
germanium
Newbie
Offline
Posts: 13
Thank You
-Given: 6
-Receive: 64
|
|
« Reply #12 on: January 10, 2014, 05:27:28 05:27 » |
|
Something that's bitten me before is if you do something like PORT |= or PORT ^= on a pin whose tristate registers aren't setup as inputs, it'll throw you for a loop. :-) I'll add a serial port class that I've used in a lot of projects. Bit long, but it's handy and only requires tweaks to the first couple functions for the hardware-specific changes. /// CPU clock speed in Hz #define PIC_CLK 32000000
/// desired serial baud rate #define BAUD 9600
/// calculate the baud rate generator divider #define DIVIDER ((PIC_CLK/(16UL * BAUD) -1))
/// defines whether to use high speed baud rates or not (setting 0 changes the divider calc) #define HIGH_SPEED 1
static unsigned char dummy;
/** * Initializes the onboard serial port hardware */ void SerialInit(void) { SPBRG = DIVIDER; //using the baudrate generator in 8-bit mode BRGH = HIGH_SPEED; //data rate for sending SYNC = 0; //asynchronous SPEN = 1; //enable serial port pins CREN = 1; //enable reception TXIE = 0; //disable tx interrupts RCIE = 1; //enable rx interrupts TX9 = 0; //8-bit transmission RX9 = 0; //8-bit reception TXEN = 0; //reset transmitter TXEN = 1; //enable the transmitter }
/// macro for clearing any UART errors #define clear_usart_errors_inline \ if (OERR) \ { \ TXEN=0; \ TXEN=1; \ CREN=0; \ CREN=1; \ } \ if (FERR) \ { \ dummy=RCREG; \ TXEN=0; \ TXEN=1; \ }
/** * Write a character to the serial port (necessary to use embedded printf calls). * * @param c character to write */ void putch(unsigned char c) { while (!TXIF); //set when register is empty { clear_usart_errors_inline; CLRWDT(); } TXREG = c; _delay(240); }
/** * Get a character from the serial port without timeout (neccessary to use * embedded scanf calls). * * @return character received from the UART */ unsigned char getch(void) { while (!RCIF) { CLRWDT(); clear_usart_errors_inline; } return RCREG; }
/** * Public function for clearing any framing or overrun errors from the serial * port hardware. */ void SerialClearErrors(void) { clear_usart_errors_inline; }
/** * Write a character to the serial port in hex. * * @param c 8 bit value to output in hex */ void SerialPutCharHex(unsigned char c) { unsigned char temp;
// transmits in hex temp = c;
c = (c >> 4); if (c < 10) c += 48; else c += 55; putch(c);
c = temp;
c = (c & 0x0F); if (c < 10) c += 48; else c += 55; putch(c); }
/** * Write an integer (16 bit) out to the serial port in hex. * * @param c Integer value to be written */ void SerialPutIntHex(unsigned int c) { #define ramuint(x) (*((unsigned int *) (x))) #define ramuint_hibyte(x) (*(((unsigned char *)&x)+1)) #define ramuint_lobyte(x) (*(((unsigned char *)&x)+0)) #define ramuchar(x) (*((unsigned char *) (x)))
SerialPutCharHex(ramuint_hibyte(c)); SerialPutCharHex(ramuint_lobyte(c));
#undef ramuint(x) #undef ramuint_hibyte(x) #undef ramuint_lobyte(x) #undef ramuchar(x) }
/** * Write an 8 bit value to the serial port in decimal form * * @param c 8 bit value to be output. */ void SerialPutCharDec(unsigned char c) { unsigned char temp;
temp = c; //hundreds if ((c / 100) > 0) putch((c / 100) + '0'); c -= (c / 100)*100;
//tens if (((temp / 10) > 0) || ((temp / 100) > 0)) putch((c / 10) + '0'); c -= (c / 10)*10;
//ones putch((c / 1) + '0'); }
/** * Write a string to the serial port. * @param str String to be written. */ void SerialPutst(register const char *str) { while ((*str) != 0) { putch(*str); if (*str == 13) putch(10); if (*str == 10) putch(13); str++; } }
|
|
|
Logged
|
|
|
|
hate
Hero Member
Offline
Posts: 555
Thank You
-Given: 156
-Receive: 355
|
|
« Reply #13 on: January 10, 2014, 12:23:34 12:23 » |
|
Something that's bitten me before is if you do something like PORT |= or PORT ^= on a pin whose tristate registers aren't setup as inputs, it'll throw you for a loop. :-)
Can you evaluate this a little further pls? What kind of a loop? The only use I can think of for changing the state of an input pin is to enable/disable the pull-up resistors on AVRs and I've never experienced any strange behavior with "PORT&=", "PORT^=" etc... on any output of any mcu architecture I've used. PICs have the output latching problem though if you were talking about that but that's unfortunately a design issue which none of the PIC18s or later have.
|
|
|
Logged
|
Regards...
|
|
|
germanium
Newbie
Offline
Posts: 13
Thank You
-Given: 6
-Receive: 64
|
|
« Reply #14 on: January 11, 2014, 06:11:59 06:11 » |
|
Sorry, by 'throwing for a loop' I just meant it can be confusing. The situation is if you don't set the port's tristate register as an input (and configure it as a digital input if that's applicable) then doing something like PORTC ^= 0x08 will not behave as you expect since it'll always read the pin in as a logic high. Simple once you realize what's gong on, but I pulled some hair out over it when I was starting
|
|
|
Logged
|
|
|
|
hate
Hero Member
Offline
Posts: 555
Thank You
-Given: 156
-Receive: 355
|
|
« Reply #15 on: January 11, 2014, 12:53:04 12:53 » |
|
Hmm, if you don't set the tristate register as input then it's set as output and to configure it as a digital input I understand it's done externally (by hardware). So you have a pin set as output and connected to an external input say a button. In that case you are mostly likely to fry the pin (ie. button is connected from pin to gnd and the pin set to high or vice versa). And the code 'PORT^=0x08' doesn't read any pins, it just toggles the 3rd pin of the PORT. The code to read the 3rd pin of a port should be something like 'some_variable=PORT&0x08', did you mean that?
Or are you trying to say that if a pin is set as output, the value read is what the pin is set at (high, low) regardless of the state of the external input as in the case above. Well that's quite obvious imo as it's been documented in datasheets and I still don't get what extraordinary problem you may have experienced with that.
|
|
|
Logged
|
Regards...
|
|
|
germanium
Newbie
Offline
Posts: 13
Thank You
-Given: 6
-Receive: 64
|
|
« Reply #16 on: January 16, 2014, 05:07:34 05:07 » |
|
I mean the latter; if it's set as an output, you read whatever the pin is set to regardless of actual state of the input. There is no extraordinary problem, just a 'gotcha'. :-)
|
|
|
Logged
|
|
|
|
|