ISR INTO_vect setup - microcontroller

I am attempting the simple task of blinking LEDs using an external interrupt. I am using an ATtiny10 so there is only one pin for interrupts (PB2).
ATtiny10_datasheet
//cpu freq set to 1MHz
#undef F_CPU
#define F_CPU 1000000UL
//io is pin/reg macros.. PB0,PORTB,etc..
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
ISR(INT0_vect) // Interrupt Service Routine for logical change on INT0 (PB2)
{
PORTB = 0X0E; //turn PB0 High
_delay_ms(2000);
}
int main(void)
{
// initializations
//DDRB 1-output,0-input
DDRB = 0x0B; // enable PB0,1,3 as outputs..PB2 is INT0 interrupt... 1011 (3,1,0)
DDRB &= ~0x04; //1011 & w/ 1011 (~0x04) keeps bits as we set them
PORTB = 0x04; // H or L for any DDRB output pins, set all Low, 0100 pulls up PB2 resistor since it is an input
EICRA |= 0x01; //any logical change on INT0 generates interrupt
sei(); //enable global interrupts
while(1){
PORTB = 0X0E; //turn PB0 on w/ LOW signal
_delay_ms(500);
PORTB = 0x0F; //turn all off again
_delay_ms(500);
PORTB = 0X0D; //turn PB1 LOW
_delay_ms(500);
PORTB = 0x0F; //turn all off again
_delay_ms(500);
}
}
MAIN QUESTION: Did I setup my interrupt incorrectly? I pulled up the internal resistor for INT0 pin PB2. I haven't been able to reach the event for interrupt yet. If additional info is needed please let me know. Thanks everyone.

The only item missing from my setup was setting the EIMSK (External Interrupt Mask) register. When set to '1' then the External Interrupt feature is enabled. Fun challenge figuring that one out! Don't skip through datasheet kids or else you end up causing more issues!!
...
EIMSK = 0x01; //enable external interrupts
EICRA |= 0x01;
sei();
...

Related

ATMEGA328P Arduino Uno: Adjusting the brightness of LED with AVR Programming

int led_pin = 9;
int duty_cycle = 63; //in %
int freq_OC = 16000; //in Hz
int freq_clk = 16000000; //in Hz
int prescaler = 1;
void setup() {
//setting the port B pin (D9) as output for OC1A to override the normal port functionality
DDRB = DDRB|(1 << led_pin);
//clearing the counter/timer registers
TCCR1A = 0;
TCCR1B = 0;
//setting the prescaler 1
TCCR1B = TCCR1B|(1 << CS10);
//setting the mode 14 fast PWM
TCCR1B = TCCR1B|((1 << WGM13)|(1 << WGM12));
TCCR1A = TCCR1A|(1 << WGM11);
//setting the fast PWM in non-inverting mode
TCCR1A = TCCR1A|(1 << COM1A1);
ICR1 = (freq_clk/(freq_OC*prescaler)) - 1;
OCR1A = ICR1/(100/duty_cycle);
}
void loop() {
}
Why doesn't this code work when pin D9 is initialised as an output pin OC1A as written above? But it works when...
DDRB = DDRB|(1 << PB1);
Is there any reason for this? As far as the datasheet for ATMEGA328P is concerned, it quotes "If one or both of the COM1X1:0 bits are written to one, the OC1X overrides the normal port functionality of the I/O pin it is connected to". So does that mean the PB1 (or D9) pin no longer functions as an I/O pin and therefore I cannot initialise it with a variable name?
DDRB is an 8-bit register, it has no 9th bit in it.
You have led_pin variable set to 9, therefore operation DDRB = DDRB|(1 << led_pin) has no effect.
There is no D9 pin on the ATmega328P. But looks like you're talking about Arduino board. You can google "Arduino UNO Pinout". E.g. this
You can see D9 pin of the board is connected to PB1 pin of the MCU. Therefore you have to use DDRB |= (1 << 1) (use value 1, not 9)

SPI on ADE7953 board

So, I've been trying to emplement a SPI communication between the board and my arduino. In the board's manual, it says that it is required to send two bytes with the address I want to read/write and another byte to choose read or write (most significant bit tells you which will apply). However, my code does not seem to be running. Anyone care to help? Code
I've not used the actual Arduino SPI library, but I will offer you an Arduino snippet that will bitbang SPI instead. It will allow you to send some bytes just to see if everything is working. It might be useful to try another approach just to see if it works. You will need to change the pins and registers to match your target application.
#define PIN_SPIDATA 16
#define PIN_SPICLK 17
#define PIN_SPILOAD 18
#define REG_DECODEMODE 0x09
#define REG_INTENSITY 0x0A
#define REG_SCANLIMIT 0x0B
#define REG_SHUTDOWN 0x0C
#define REG_DISPLAYTEST 0x0F
void setup() {
// set ddr for sw spi pins
pinMode(PIN_SPICLK, OUTPUT);
pinMode(PIN_SPIDATA, OUTPUT);
pinMode(PIN_SPILOAD, OUTPUT);
setRegister(REG_INTENSITY, 0x04);
setRegister(REG_SCANLIMIT, 0x07);
setRegister(REG_SHUTDOWN, 0x01); // normal operation
setRegister(REG_DECODEMODE, 0x00); // pixels not integers
setRegister(REG_DISPLAYTEST, 0x00); // not in test mode
}
// sends a single byte by sw spi (no latching)
void putByte(uint8_t data)
{
uint8_t i = 8;
uint8_t mask;
while(i > 0) {
mask = 0x01 << (i - 1); // get bitmask
digitalWrite(PIN_SPICLK, LOW); // tick
if (data & mask){ // choose bit
digitalWrite(PIN_SPIDATA, HIGH); // set 1
}else{
digitalWrite(PIN_SPIDATA, LOW); // set 0
}
digitalWrite(PIN_SPICLK, HIGH); // tock
--i; // move to lesser bit
}
}
// sets register to the same byte value for all screens
void setRegister(uint8_t reg, uint8_t data)
{
digitalWrite(PIN_SPILOAD, LOW); // begin
for(uint8_t i = 0; i < numChips; ++i){
putByte(reg); // specify register
putByte(data); // send data
}
digitalWrite(PIN_SPILOAD, HIGH); // latch in data
digitalWrite(PIN_SPILOAD, LOW); // end
}

How do I have this audio and LED activate ONLY when a button is held using an Arduino?

I have this code that I am using to play a sound effect where I used a program called wav2c to convert a .wav file to number values that I put into a header file that I use in the code to generate the sound. I currently have it programmed to play the audio upon uploading it to the Arduino with an LED being activated along with it and staying lit for just the duration of the sound effect. I am trying to program it so that the sound and LED only activate when I am pressing a button. I have the pin the button is plugged into already programmed in but I'm not sure how to have it control the audio and LED as stated above. I don't have much experience with programming or Arduino so any help is much appreciated! I am using an Arduino Mega 2560.
The code
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#define SAMPLE_RATE 20000
#include "Test.h"
int ledPin = 2;
int speakerPin = 9; // Can be either 3 or 11, two PWM outputs connected to Timer 2
const byte pinSwitch1 = 3;
volatile uint16_t sample;
byte lastSample;
void stopPlayback()
{
digitalWrite(ledPin, LOW);
// Disable playback per-sample interrupt.
TIMSK1 &= ~_BV(OCIE1A);
// Disable the per-sample timer completely.
TCCR1B &= ~_BV(CS10);
// Disable the PWM timer.
TCCR2B &= ~_BV(CS10);
digitalWrite(speakerPin, LOW);
}
// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
if (sample >= sounddata_length) {
if (sample == sounddata_length + lastSample) {
stopPlayback();
}
else {
if(speakerPin==11){
// Ramp down to zero to reduce the click at the end of playback.
OCR2A = sounddata_length + lastSample - sample;
} else {
OCR2B = sounddata_length + lastSample - sample;
}
}
}
else {
if(speakerPin==11){
OCR2A = pgm_read_byte(&sounddata_data[sample]);
} else {
OCR2B = pgm_read_byte(&sounddata_data[sample]);
}
}
++sample;
}
void startPlayback()
{
pinMode(speakerPin, OUTPUT);
// Set up Timer 2 to do pulse width modulation on the speaker
// pin.
// Use internal clock (datasheet p.160)
ASSR &= ~(_BV(EXCLK) | _BV(AS2));
// Set fast PWM mode (p.157)
TCCR2A |= _BV(WGM21) | _BV(WGM20);
TCCR2B &= ~_BV(WGM22);
if(speakerPin==11){
// Do non-inverting PWM on pin OC2A (p.155)
// On the Arduino this is pin 11.
TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set initial pulse width to the first sample.
OCR2A = pgm_read_byte(&sounddata_data[0]);
} else {
// Do non-inverting PWM on pin OC2B (p.155)
// On the Arduino this is pin 3.
TCCR2A = (TCCR2A | _BV(COM2B1)) & ~_BV(COM2B0);
TCCR2A &= ~(_BV(COM2A1) | _BV(COM2A0));
// No prescaler (p.158)
TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set initial pulse width to the first sample.
OCR2B = pgm_read_byte(&sounddata_data[0]);
}
// Set up Timer 1 to send a sample every interrupt.
cli();
// Set CTC mode (Clear Timer on Compare Match) (p.133)
// Have to set OCR1A *after*, otherwise it gets reset to 0!
TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));
// No prescaler (p.134)
TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);
// Set the compare register (OCR1A).
// OCR1A is a 16-bit register, so we have to do this with
// interrupts disabled to be safe.
OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000
// Enable interrupt when TCNT1 == OCR1A (p.136)
TIMSK1 |= _BV(OCIE1A);
lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);
sample = 0;
sei();
}
void setup()
{
pinMode( pinSwitch1, INPUT );
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
startPlayback();
}
void loop()
{
while (true);
}
The header file referenced in the code with the numeric values to create the audio.
#ifndef _HEADERFILE_H // Put these two lines at the top of your file.
#define _HEADERFILE_H // (Use a suitable name, usually based on the file name.)
const int sounddata_length=32000;
//const int sounddata_sampleRate=20000;
const unsigned char sounddata_data[] PROGMEM = {
15,1,49,0,150,0,138,0,219,255,133,0,176,0,15,1,210,
//There are many lines of more numbers in between that I cut out to save space
};
#endif // _HEADERFILE_H // Put this line at the end of your file.
The following changes will allow you to start playback whenever there is a falling edge on your switch pin. You may need to tweak to avoid switch 'bouncing'.
Firstly, add a global variable to record the last switch state:
int lastSwitchState;
Change your setup() to
void setup() {
pinMode(pinSwitch1, INPUT);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, HIGH);
lastSwitchState = digitalRead(pinSwitch1);
}
and your loop() function to
void loop() {
delay(50);
int switchState = digitalRead(pinSwitch1);
if (switchState != lastSwitchState) {
lastSwitchState = switchState;
if (switchState == LOW) {
startPlayback();
}
}
}
Interrupts vs polling
Instead of polling the switch pin inside the main loop(), you could use interrupts. You would use attachInterrupt() to do this. Interrupts are only available on certain pins, however, and the above approach is conceptually simpler I think.

Atmega328 Analog-to-Digital Converter

I am working on understanding ADC with an arduino and a LCD shield that has buttons. I like to work in Atmel Studio and work to write my own libraries through research and the datasheet. My goal is to write the ADC value to the screen. If I write an Arduino Sketch with the analogRead() function it works, but I can not get it to read anything on the LCDw with my Atmel Studio program. The LCD does work as I can write other information on the LCD. My program is below. Any ideas would really help. Thanks!!!
Analog Header
#include<util/delay.h>
void adc_init(void)
{
ADMUX = (1<<REFS0); //select AVCC as reference
ADCSRA = (1<<ADEN) | 7; //enable (ADEN) and prescale = 128 (16MHz/128 = 125kHz)
}
int readAdc(char chan)
{
ADMUX = (1<<REFS0) | (chan & 0x0f); //select ref (REFS0) and channel
ADCSRA |= (1<<ADSC); //start the conversion
while (ADCSRA & (1<<ADSC)); //wait for end of conversion
return ADC; //Return 16 Bit Reading Register
}
Main Program
#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz clock speed
#endif
#define D4 eS_PORTD4
#define D5 eS_PORTD5
#define D6 eS_PORTD6
#define D7 eS_PORTD7
#define RS eS_PORTB0
#define EN eS_PORTB1
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "lcd328.h"
#include "myHeader328.h"
/*--------------------------------------------------------
-- initScreen() initializes the screen
--------------------------------------------------------*/
void initScreen()
{
Lcd4_Init(); //Initialize Screen
Lcd4_Clear(); //Clear Screen
Lcd4_Set_Cursor(1,0);
Lcd4_Write_String("Count:0");
}
/*--------------------------------------------------------
-- refreshScreen() refreshed the screen
--------------------------------------------------------*/
void refreshScreen(int count2)
{
char countStr[5];
sprintf(countStr, "%i", count2);
Lcd4_Set_Cursor(1,6);
Lcd4_Write_String(countStr);
_delay_ms(50);
}
/*--------------------------------------------------------
-- main()
--------------------------------------------------------*/
int main(void)
{
DDRD = 0xFF;
DDRB = 0xFF;
DDRC = 0x00;
initScreen();
PORTB = PORTB | (1<<PORTB2); //Turn on backlight
int adcOut = 4;
while(1)
{
adcOut = readAdc(0);
refreshScreen(adcOut);
_delay_ms(500);
}
}
You had to call adc_init() in your main loop.
/*--------------------------------------------------------
-- main()
--------------------------------------------------------*/
int main(void)
{
DDRD = 0xFF;
DDRB = 0xFF;
DDRC = 0x00;
initScreen();
adc_init(); //!!!!!
PORTB = PORTB | (1<<PORTB2); //Turn on backlight
int adcOut = 4;
while(1)
{
adcOut = readAdc(0);
refreshScreen(adcOut);
_delay_ms(500);
}
}

NRF24L01 with ATTiny and Uno not connecting

I have an ATTiny85 connected to an NRF24L01+ module using this wiring diagram: diagram. The ATTiny85 periodically goes in and out of sleep to send some value to a receiver, an Arduino Uno. If the ATTiny is running off the Arduino power supply (3.3v), everything works correctly. When I run the ATTiny off of a separate CR2032 coin cell that delivers around 3v, the Arduino never receives any data. I have a status LED hooked up to the ATTiny to ensure that the ATTiny is waking correctly, which it is. Here's the code for both:
EDIT:
Connecting it to an external 3.3v not from the Uno makes everything work - why wouldn't the coin cell's voltage work? I think everything is rated below 2.8v, the CR2032 minimum.
ATTiny Code
#include <avr/sleep.h>
#include <avr/interrupt.h>
// Routines to set and claer bits (used in the sleep code)
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
#define CE_PIN 3
#define CSN_PIN 3 //Since we are using 3 pin configuration we will use same pin for both CE and CSN
#include "RF24.h"
RF24 radio(CE_PIN, CSN_PIN);
byte address[11] = "SimpleNode";
unsigned long payload = 0;
void setup() {
radio.begin(); // Start up the radio
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(15,15); // Max delay between retries & number of retries
radio.openWritingPipe(address); // Write to device address 'SimpleNode'
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);
delay(500);
digitalWrite(4, LOW);
delay(500);
digitalWrite(4, HIGH);
delay(500);
digitalWrite(4, LOW);
delay(500);
digitalWrite(4, HIGH);
delay(500);
digitalWrite(4, LOW);
delay(1000);
setup_watchdog(6);
}
volatile int watchdog_counter = 0;
ISR(WDT_vect) {
watchdog_counter++;
}
void loop()
{
sleep_mode(); //Go to sleep!
if(watchdog_counter >= 5)
{
digitalWrite(4, HIGH);
watchdog_counter = 0;
payload = 123456;
radio.write( &payload, sizeof(unsigned long) ); //Send data to 'Receiver' ever second
delay(1000);
digitalWrite(4, LOW);
}
}
//Sleep ATTiny85
void system_sleep() {
cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF
set_sleep_mode(SLEEP_MODE_PWR_DOWN); // sleep mode is set here
sleep_enable();
sleep_mode(); // System actually sleeps here
sleep_disable(); // System continues execution here when watchdog timed out
sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON
}
// 0=16ms, 1=32ms,2=64ms,3=128ms,4=250ms,5=500ms
// 6=1 sec,7=2 sec, 8=4 sec, 9= 8sec
void setup_watchdog(int ii) {
byte bb;
int ww;
if (ii > 9 ) ii=9;
bb=ii & 7;
if (ii > 7) bb|= (1<<5);
bb|= (1<<WDCE);
ww=bb;
MCUSR &= ~(1<<WDRF);
// start timed sequence
WDTCR |= (1<<WDCE) | (1<<WDE);
// set new watchdog timeout value
WDTCR = bb;
WDTCR |= _BV(WDIE);
}
Receiver Code
#define CE_PIN 7
#define CSN_PIN 8
#include <SPI.h>
#include "RF24.h"
RF24 radio(CE_PIN, CSN_PIN);
byte address[11] = "SimpleNode";
unsigned long payload = 0;
void setup() {
while (!Serial);
Serial.begin(115200);
radio.begin(); // Start up the radio
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(15,15); // Max delay between retries & number of retries
radio.openReadingPipe(1, address); // Write to device address 'SimpleNode'
radio.startListening();
Serial.println("Did Setup");
}
void loop(void){
if (radio.available()) {
radio.read( &payload, sizeof(unsigned long) );
if(payload != 0){
Serial.print("Got Payload ");
Serial.println(payload);
}
}
}
Is the problem here that the ATTiny and Uno need to be turned on at the same time to establish a connection, or is it something to do with the battery, or something else entirely? Any help would be appreciated.
I'm experiencing the same problem when running Arduino Nano from a battery.
Nano has a 3.3V pin that I'm using for powering the NRF24L01+ module.
When the voltage from my battery-pack drops under 3.3V, the 3.3V pin voltage also drops. After few minutes, the RF module is not sending any messages.
I fixed the problem temporarily by routing the battery through a 12V step-up regulator that I bought earlier for a different project. These 12V then go to the "UN" pin on Nano which accepts 6-20V. This setup works nicely but is definitely not optimal.
Therefore I'm planning to use a 3.3V step-up regulator such as Pololu 3.3V Step-Up Voltage Regulator U1V11F3 which, according to the supplier, can efficiently generate 3.3V from input voltages as low as 0.5V.
I think this might be helpful to your project as well.

Resources