Tearing my hair out... again! - Page 1
Forum section: electronics / projects

author: MrAureliusR
author_rank: Unknown
timestamp: March 19, 2014, 06:50:16 am
content: Let me just start by saying that, while I wouldn't consider myself a 'guru', I know AVR-GCC very well. I have used AVRs for quite a while now. I also use TI ARMs so my knowledge of C is quite good.However, I've recently begun to play around with Arduino. Apparently, this was a mistake as now I can't even do the most basic things. To my knowledge, technically you should be able to insert 'regular' AVR C wherever you want? For example, you can use the Arduino APIs to do basic things like digitalWrite, digitalRead, using Serial.print, etc. And then, in the same function, pull something likeTCCR0A |= (1<<COM0A1)|(1<<WGM01)|(1<<WGM00); // set up OC0A as PWM (digital pin 6)OCR0A = 0x80;TCCR0B |= (1<<CS01)|(1<<CS00);Now, in very basic testing, this seems to work. What I'm trying to do is when the user pushes a button, the PWM turns on. When they stop pushing the button, it turns off. You'd think this was ridiculously, intelligence-insulting simple, right?Apparently not...I've been trying something like this, after setting up PWM and input/output pins in setup(). If I just turn the PWM on, it works fine. However, the second I introduce the switch/if statements, and the digitalRead of the button, it just does nothing, OR the PWM just stays on.void loop(){delay(50);toneStatus = digitalRead(buttonPin);switch(toneStatus){case LOW:OCR0A = 0x80; // %50 duty cycleTCCR0B |= (1<<CS01)|(1<<CS00); // clock rate of IO/64 = 250kHz, @ 0xFF TOP = ~970HzSerial.println("PWM started");break;case HIGH:TCCR0B &= ~(1<<CS01);TCCR0B &= ~(1<<CS00);Serial.println("PWM stopped");break;default:TCCR0B &= ~(1<<CS01);TCCR0B &= ~(1<<CS00);Serial.println("Default off");break;}}I've also tried putting case 0: and case 1:, tried putting the TCCR0B &= statements on the same line (from everything I've read in the datasheet, seeing as how writing a 1 to the CS00/CS01 starts the clock, it seems to follow that writing 0s to them would stop them?).I orignally didn't even use the loop(), I was just doing an external interrupt on the logic change of the button, and then calling a function to start or stop the PWM. This wasn't working either. It seems that the interrupt wasn't triggering, even though I was watching the pin with my scope. Also, when I had the PWM enable in the interrupt, it STILL started making noise even when the interrupt hadn't been triggered. Now THAT one I couldn't figure out.Any experienced Arduino people around? I would much rather just program it in C but I'm going to be teaching a little bit of Arduino to people and I need to understand WTF is going on with it.Thanks SO VERY MUCH in advance!

author: Pat Pending
author_rank: Regular Contributor
timestamp: March 19, 2014, 07:07:57 am
content: Where's the code for the pullup?

author: MrAureliusR
author_rank: Unknown
timestamp: March 19, 2014, 07:08:34 am
content: @Pat -- I'm using an external pullup.I think I just solved it.For reference, for anyone in the future who is mixing AVR-C and Arduino...The problem appeared to be the Arduino's delay() function. For some bizarre reason, it was only executing the code ONCE in the loop section. Even if I added while(1){} around it!!I added #include <util/delay.h> and changed it to _delay_ms(50) and suddenly it came to life...That was literally the LAST statement I suspected. I spent an hour agonizing over my switch() statement. I was getting bizarre behaviour -- it was going through the switch() statement once, and printing both "PWM stopped" and "Default off" and then it would seemingly halt. So I ditched the default: statement, changed the delay() and ... now it works perfectly.Might go back to interrupts now as I dislike loops.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: March 19, 2014, 08:06:17 am
content: Beware optimization settings; timing loops may have to be marked asvolatileor forced with compiler hooks to implement properly.Tim

author: domagoj
author_rank: Newbie
timestamp: March 19, 2014, 01:40:22 pm
content: Hi,delay() function internally uses micros() function, which in turn relies on Timer 0. So directly modifying Timer 0 registers will break delay(). I think it would have work for you if you used Timer 1 in your PWM code.You can examine the source code for those functions in wiring.c (https://code.google.com/p/arduino/source/browse/trunk/hardware/cores/arduino/wiring.c?r=565) which you can find inside hardware/cores/arduino/ folder inside your Arduino distribution.Also there is an option of using Timer1 or Timer3 Arduino libraries for PWM -http://playground.arduino.cc/Code/Timer1