How did you guys made the switch?? - Page 1
Forum section: electronics / beginners

author: SuperMiguel
author_rank: Regular Contributor
timestamp: June 21, 2012, 03:59:58 am
content: How did you guys made the switch between C software programming to microcontrollers C programming??I mean i know both are C, but for some reason (maybe missing lots of practice)but im able to program lets say a full Poker game with multiple players in C.. But im having hard time understanding this dumb code?Code://LED Flashing#include <avr/io.h>#include <util/delay.h>#ifndef cbi#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))#endif#ifndef sbi#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))#endifint main(void){sbi(DDRD,1);while(1){sbi(PORTD,1); //This will turn ON LED_delay_ms(4000);cbi(PORTD,1); //This will turn OFF LED_delay_ms(4000);}return 0;}

author: ftransform
author_rank: Frequent Contributor
timestamp: June 21, 2012, 04:06:44 am
content: Try going to a website dedicated to educating it with VERY simple examples stead of looking at sample code (which I found was difficult to understand (when it was written by the Microchip corporation)). But I know what you mean programming it for the computer seems MUCH easier...

author: SuperMiguel
author_rank: Regular Contributor
timestamp: June 21, 2012, 04:09:55 am
content: Quote from: ftransform on June 21, 2012, 04:06:44 amya just like arduino it seems like a joke to program some times.. Use libs/libs/libs i know most ppl dont want to re inviten the wheel and use pre made libs. But i feel like im not learning...Also in software programming in C... even tough im still using libs i feel like i really know what im doing, and that im really doing C.Trying to read avr C is a bit hard... :S

author: amspire
author_rank: Super Contributor
timestamp: June 21, 2012, 04:20:12 am
content: Not sure where you are having a problem. It is all standard CCode://LED Flashing#include <avr/io.h> // if you follow the links, you will get to srf_defs.h with the definitions of the _BV() macro and the _SRF_BYTE() macro.#include <util/delay.h> // This will contain the definition of _delay_ms()#ifndef cbi#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) // define a macro for cbi - clear bit on port "srf"#endif#ifndef sbi#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) // define a macro for sbi - set bit on port "srf"#endifint main(void){sbi(DDRD,1); // Sets the Data Direction port of PORTD for bit 1 to be an output.while(1) //loop forever{sbi(PORTD,1); //This will turn ON LED - set bit 1 on port PORTD_delay_ms(4000); // wait 4 secondscbi(PORTD,1); //This will turn OFF LED - clear bit 1 on port PORTD_delay_ms(4000); // wait another 4 seconds}return 0; //never gets here - I have no idea why they even put it in. You do not normally ever return out of the main() function.}

author: SuperMiguel
author_rank: Regular Contributor
timestamp: June 21, 2012, 04:24:36 am
content: port declaration and port use mostly

author: JuKu
author_rank: Frequent Contributor
timestamp: June 21, 2012, 04:28:58 am
content: You are not supposed to understand those without reading the data sheet.

author: Psi
author_rank: Super Contributor
timestamp: June 21, 2012, 05:18:33 am
content: Those two #ifndef bits are just making sure cbi and sbi macros exist in a library already, if not it creates them.As far as i know cbi and sbi are pretty much standard and already defined. So you could probably delete all that #ifndef stuff and it would compile fine.You could also set and clear the pins yourself and not even use the cbi sbi macros (which stand for 'clear bit' and 'set bit')For example...Using the sbi macro to set bit 5 on the DDRD register goes like thissbi(DDRD,5);Which is the same as doing it yourself manuallyDDRD = DDRD | (1<<5)or, you can simplify it using =|DDRD |= (1<<5);It's a good idea to use the actual PIN definition instead of a number since it's easier to readSo if this particular pin5 is on PORTD you could use PD5 instead of the number 5DDRD |= (1<<PD5);To clear a bit it's a little more complicated but if you write it down and work it out it makes perfect sense.DDRD &= ~(1<<PD5);If you look at the cbi/sbi macros you will see they are actually doing exactly the same thing.Note the "_BV()" and "~_BV()" sections which i believe is yet another macro for (1<<X) and ~(1<<X)In microcontroller C you see much more use of macros because for small things, like setting a pin, a function is overkill and eats up cycles calling and returning from the function.It's faster to make it a macro that is replaced at compile time.

author: Mechatrommer
author_rank: Super Contributor
timestamp: June 21, 2012, 05:39:20 am
content: Quote from: Psi on June 21, 2012, 05:18:33 ammostly its for compatibility, portability and assurance reason. its fine as long as you working with avr environment, but say we want to port the code to pic MPLAB, which i think does not use sbi or cbi opcode/notation.if the OP understands how bit operations and mcu IO pins work, then he should have no problem understanding those 'dumb' code. its not dumb, but the lowest level implementation of the "full poker game" which has been hidden away from higher level programmer.

author: SuperMiguel
author_rank: Regular Contributor
timestamp: June 21, 2012, 03:41:10 pm
content: Quote from: Psi on June 21, 2012, 05:18:33 amSo this: DDRD |= (1<<PB5); makes the pin HIGH and DDRD &= ~(1<<PB5); makes it LOW.. And to know what PB5 is ill look in the datasheet.. But where does DDRD comes from? or what is it?

author: free_electron
author_rank: Super Contributor
timestamp: June 21, 2012, 05:05:16 pm
content: DDRD data direction register ...you need to look at how the io port works. every manufacturer , or even different devices from the same manufacturer , have their own mode of operation.you need to set up some reigsters telling the cpu which pins are input , which are output. ( data driection )then there is a register that lets you set the output pins high or low and there is another register where you can read the inputs.other cpu's may simply have 1 register. set a pin high to make it input read from the register to get everything back.it depends on the machine.this has NOTHING to do with the programming language chosen. it is hardware config. this can only be done by reading the datasheet. it is all explained in detail. the register names , what the bits do and how the port works.every cpu is different...

author: Kremmen
author_rank: Super Contributor
timestamp: June 21, 2012, 08:10:48 pm
content: DDRD = specifically, the Data Direction Register for port D.Many AVR chips have the GPIO (general purpose I/O) mapped into memory such that you have an address to SET, to CLEAR or directly write into a port or port bit. Thus writing a "1" to a pin's clear address will reset that pin (provided it was defined as an output, that is), and writing a "1" to a set address for the same pin will turn it on. It all varies and as already noted, the chip data sheet is your friend.

author: Unknown
author_rank: Unknown
timestamp: June 21, 2012, 08:20:11 pm
content: sbi/cbi are even deprecated by avr-libc in favor of the bit operations that PSI mentions (eg. PORTB |= (1 << PB5) or PORTB |= _BV(PB5)).

author: typeglob
author_rank: Contributor
timestamp: June 21, 2012, 10:10:26 pm
content: Quote from: alm on June 21, 2012, 08:20:11 pmNaming those after their assembly language equivalents (sbi and cbi) wasn't a very good idea to start with.

author: caroper
author_rank: Regular Contributor
timestamp: June 21, 2012, 11:53:55 pm
content: I actually had the opposite problem in that I have used Assembler exclusively for years on micro's and mainframes and was suddenly tasked with programming in C.After several days of panic and trying to digest all kinds of confusing C tutorials, a friend of mine told me that C is nothing more than a portable assembler that has been adapted, through the use of extensive Libraries and API's, into a high level language for PC's etc.He then took me through pointer arithmetic, which I instantly recognized as indirect addressing, and suggested I ditch all the reference books I had acquired (apart from K&R) and rather read each *.h file that I needed to include so that I could see what functions it offered.I had my first bit of code up and running 2 hours later.I am still far from being a C programmer, but at least now I realise that on a uC platform, C is NOT a high Level language, treat it as an assembler and learn the register names from the Datasheet of the device and the device Header Files.I hope that rather obtuse way of looking at it helpsCheersChrisp.s. I should add that my part of the project was the hardware abstraction layer, the actual application was written by the friend.I still do not have a full grasp of all the standard C libraries.The combination worked well though. He could concentrate on the data encryption and protocol stacks whilst I could read his data in and out of the hardware and move it between devices.My quest to understand C continues and I don't see myself ever going back to assembler now that I have tasted the power of C.

author: westfw
author_rank: Super Contributor
timestamp: June 22, 2012, 02:31:06 am
content: QuoteWhy not? They do the same thing. Probably in the distant past they were defined with inline assembler, and were only generalized when the compiler got good enough to generate the single instructions on its own. (Oh, I guess that makes it not c-like.)As for the original question... Learning at least one assembly language reasonably well would be a big help in understanding "C for microcontrollers." In theory, it shouldn't be necessary, but in reality there are extenuating circumstances:1) Most datasheets are still written "in assembler." You get definitions of the bits in a hardware IO register, rather than some C abstraction.2) A lot of the operations common in embedded devices, such as setting individual bits in memory-mapped locations, are just not very common in desktop C. You can program in C for years and never need to understand binary, for instance. That's much less true of most assemblers...

author: Psi
author_rank: Super Contributor
timestamp: June 22, 2012, 11:12:13 am
content: yeah sorry, i got that wrong in my exampleIf you're working on the port D direction register it's going to be PD5 (not PB5, which is for PORT B)So..DDRD |= (1<<PD5);Though in most cases the code will run fine as PD5 = 5 and PB5 is also = 5But in some MCUs pins are in odd locations so you should always use the correct PIN definition for each PORT.For AVRs it's basically..Use PORTn for setting the state of a pin or portUse DDRn for setting the direction of a pin or portUse PINn for reading the value of a pin or portAnd you have Pn0 to Pn7 for each port that provides a bit offset for each pinWhere "n" is the port letter A-ZThere's lots of interactions/modes between each of those registers that let you create- Sinking only pins- Sourcing only pins- Source and sink pins- Input pins- Input pins with enabled internal pullupetc.It's all in the datasheet.

author: typeglob
author_rank: Contributor
timestamp: June 23, 2012, 12:14:40 pm
content: Quote from: westfw on June 22, 2012, 02:31:06 amBecause they imply a one-to-one relation, which may not always be the case. Also, that instruction in assembler is AVR specific, but in C it isn't. You bring up good points though.I often find the abstractions like digitalWrite in the AVR C library waaaay toooo sloooow. They do a lot of checking and contain abstraction which is nice at times, but not if you are trying to do bit banging with some measure of accuracy. Accessing the IO registers directly from C (or even inline assembly) solves that though.Quote from: westfw on June 22, 2012, 02:31:06 amVery good advice.

author: Mechatrommer
author_rank: Super Contributor
timestamp: June 23, 2012, 12:56:10 pm
content: Quote from: typeglob on June 23, 2012, 12:14:40 pmi'll do this for personal project and not having to remember what asm instruction for other mcu. i just have to remember one opcode (in this case avr) to enable interrupt for all pic, avr arm etc.Quote from: typeglob on June 23, 2012, 12:14:40 pmbecause it was done by "artist(s)". and the price for checking and table lookup for appropriate pin assignment must be taken into consideration whether needed or not. most newbies are happy with it up to some point, alas thats what makes arduino so popular in "artist" like community (maybe including me).

author: westfw
author_rank: Super Contributor
timestamp: June 23, 2012, 11:20:26 pm
content: QuoteIntellectually, I agree. In practice, I rarely find it to be TOO slow. Writing directly to IO ports starts to get fast enough that you have to remember your EE/Physics when dealing with the signal. The number of people who want to go to an 80MHz ARM so they can bitbang faster through the three-foot ribbon cable connected to their protoboard is a bit scary...Abstraction and error checking ARE expensive. Not having them is expensive in other ways :-(

author: typeglob
author_rank: Contributor
timestamp: June 24, 2012, 01:39:05 am
content: My scope is my favorite uC debugging tool. However, I need to be able to quickly toggle the status of an output, because if it takes too long it has too much of an impact on whatever I try to debug.I'm messing around with MIDI stuff and running multiple software UARTs is not ideal, especially when you need to use digitalWrite. I'm trying to get my head around FPGA programming (oh noes, another software guy who thinks you 'program' FPGAs) since for this kind of stuff an FPGA or even a combination of a uC and an FPGA seems to be a good fit.

author: westfw
author_rank: Super Contributor
timestamp: June 24, 2012, 01:48:23 am
content: Oh, there are certainly times that digitalWrite() is too slow. Just not nearly as often as people think, nor as often as you'd sort of like it to be to justify bypassing it. I keep remembering all those problems solved by interpreted BASICs running on really slow platforms (BASIC-52, Stamp BASIC.) (or, say, bit-banging out the serial port control lines with a windows system call for each transition!)