Servos not running properly on AVR - c

I'm not gonna waste your time, and just post the code along with the explanation
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
int main(void){
sei(); //Enable interrupts
DDRB = (1 << PORTB3);//Set pin P3 as an output and other pins as inputs
//PORTB = 0xff;
DDRA = (1 << PORTA7);//Set pin A7 as an output and other pins as inputs
//PORTA = (1 << PORTA7);
TCCR0 = (1 << WGM00) | (1 << WGM01) | (1 << COM01);//Enable PWM, and configure Timer
TIMSK = (1 << TOIE0);//Enabling an interrupt
OCR0 = 255;//Setting comparison value for the Output compare unit
TCCR0 |= (0b110 << CS00);//Selecting the clock as the falling edge on a certain pin
while(1){
/*
* The portion of the code creates a square wave with a period of 39 us, which means that the falling edge occurs at a period of 78us, and since the output period of
* the PWM is 50Hz for a servo, that fits perfectly (1/(79*10^-6 * 256) ~ 50), but for some reason, the servo doesn't move...*/
PORTA ^= (1<< PORT7);
_delay_us(39);
}
}
So, what's the problem?? I don't really have an oscilloscope to measure the frequency, so don't ask me to do that, but a peculiar thing that I did notice was that the voltage across the servo power wires was 2.7V when it should've been 5V, but the power supply itself was supplying 5V, and this only happened when I connected the signal pin to the PWM pin, and it happened regardless of whether the 5V rail was connected to the servo or not... Any ideas on what the problem is??

Your PWM output has a 50% duty cycle, so the effective port output voltage is reduced from 5v to 2.5v when measured with a voltmeter. Assuming you are measuring the voltage against Ground, it won't make any difference if 5v power line is connected to the servo, but it will make a difference if the PWM signal is not connected.
If the servo is bidirectional, then it is possible that the 50% duty cycle keeps it stationary - try a different duty cycle, it looks as if you have hard coded the PWM period, inverting the output every half-cycle. Try something like
PORTA ^= (1<< PORT7);
_delay_us(28);
PORTA ^= (1<< PORT7);
_delay_us(50);

Related

Unable to operate the timer overflow interrupt on AVR

I am trying to implement a 16-bit timer overflow interrupt on the ATMEGA168. The idea is to write a message to the UART I/O register when the timer overflows.
I've tested the UART separately and it works fine via RealTerm (baudrate of 9600 bits/s).
I created a base project from https://start.atmel.com/#dashboard where I had to set the input clock frequency to 16MHz to be compatible with the debugger (see page 5). So I would expect to see a 0x1 on my serial terminal every (16x106 / 1024)-1 x 216 = 4.194 seconds.
However, I'm not seeing anything on the terminal regardless of the prescaler I select. Can anyone please advise what could be going wrong?
I have attached the ISR and the main() below:
#include <atmel_start.h>
#include <stdio.h>
#include <usart_basic.h>
#include <atomic.h>
#include <avr/interrupt.h>
#include <avr/io.h>
// timer1 overflow
ISR(TIMER1_OVF_vect) {
// Send 0x1 over UART
UDR0 = 0x1;
}
int main(void) {
atmel_start_init();
// enable timer overflow interrupt for Timer1
TIMSK1 = (1<<TOIE1); // also tried |=
// start 16-bit counter with /1024 prescaler
TCCR1B = (1 << CS10) | (1 << CS12); // also tried |=
TCCR1A = 0x0;
// enable interrupts
sei();
while(true) {
// more code here...
}
}
I have tried to isolate the problem by not writing to UART in the ISR, but just incrementing a counter (declared with the volatile qualifier) and then printing its value to the screen via UART in the while(true) loop. But the counter doesn't increment either and remains stuck at 0.
You have no USART initialisation code. Specifically you don't enable the transmitter or set the baud rate. I accept that you have tried it with a counter, but that is not the code shown so we can come to no conclusion about its correctness or otherwise.
Without initialisation, the transmitter will not run, and the baud rate will be 1Mbps. Your need at least:
// Set baud rate 9600
uint16_t brr = (FOSC / 16 / 9600) - 1
UBRR0H = (uint8_t)(ubrr >> 8);
UBRR0L = (uint8_t)ubrr;
// Enable transmitter
UCSR0B = (1<<TXEN0);
// Note reset state frame is N,8,1
I am not convinced that it matters but your timer initialisation order is not idiomatic. You would normally enable the interrupt after setting the prescaler and any other configurations, and to ensure the first period is a complete period, reset the counter to zero immediately before enabling interrupts.
// set up timer with prescaler = 1024
TCCR1B = (1 << CS12) & (1 << CS11);
// initialise counter
TCNT1 = 0;
// enable overflow interrupt
TIMSK = (1 << TOIE1);
// enable global interrupts
sei();
As I said, I am not sure that will fix your problem but the elided part:
while(true) {
// more code here...
}
may well be the code that is breaking it. You would do well to discount that possibility by disabling or removing any code there temporarily.

AVR CTC Timer Frequency Apparent Inaccuracy

I'm a beginner with programming AVR devices, in an attempt to move away from the inefficient _ms_delay() and _us_delay() blocking functions I've been trying program using the built in timers to control the timing of a basic LED flashing program with the CTC timer mode on a 16-bit timer. My goal is to make the LED flash at 2 Hz, on for 0.5s, off for 0.5s.
According to the ATMega328P datasheet, the freqency of a CTC output should be f_CTC = f_Clock/(2N(OCR1A+1), since my chip is a 328P Xplained mini, it's default CPU speed is 16 MHz, using the above formula, with N=64, the required OCR1A value to achieve my desired frequency should be 62499. With all of this in mind I wrote the following code:
#include <avr/io.h>
int main(void)
{
// Setup for timer TC1 (16-bit) in CTC mode to run at 2 Hz
TCCR1A = 0x00;
OCR1A = 62499; // Sets time resolution to 0.5 s
TCCR1B = 0x0b;
TCCR1C = 0x00;
// Set pin directions
PORTD &= ~(1<<PORTD6);
DDRD |= (1<<DDD6);
while (1)
{
if(TIFR1 & (1<<OCF1A))
{
PORTD ^= (1<<PORTD6);
}
TIFR1 |= (1<<OCF1A);
}
}
However, when I run the code the LED flashes at a frequency of 1 Hz, which I was able to time with my phone. Additionally, when I change OCR1A to 31249, which should increase the frequency to 4 Hz it seems to be flashing at 8 Hz, or on-and-off 4 times per second. I feel like I'm misunderstanding something about how CTC mode works, if someone could explain it simply to me, or any other issues with my code, I would be grateful.
I noticed one thing that could cause the issues you are seeing.
You are using the line TIFR1 |= (1<<OCF1A); to clear the OCF1A bit. You are running that line very frequently, so there is a high chance that when OCF1A gets set, your code just clears it immediately before the if statement can see that it was set. You have no control over when that bit gets set; it can happen at any point in your loop.
You should only clear OCF1A after verifying that it is 1, like this:
if (TIFR1 & (1 << OCF1A))
{
PORTD ^= (1 << PORTD6);
TIFR1 |= (1 << OCF1A);
}

Designing a reaction timer for atmega328p microcontroller using C

Basic description of what I have to do :
The "reaction timer" is an embedded system that measures the user's reaction time to a signal and displays it in a scale of three LEDs. When the user presses the "ready" pushbutton on the system, the "reaction timer" turns off all LEDs in the system and waits for a random amount of time between 1 and 10 seconds. Upon the expiration of this waiting time, the "reaction timer" turns on a blue LED and signals to the user. The user then presses the "react" pushbutton on the system as quickly as possible to react to the signal. The "reaction timer" then turns off the blue LED used to signal and measures the time elapsed between the signal and the user's reaction to the signal. If the user's reaction time to signal is less than one second, greater than one second but less than two seconds or greater than two seconds, the "reaction timer" turns on a green, orange or a red LED, respectively to display the user's performance.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h> //library includes srand(), rand() methods
#include <time.h> //library include time()
#define F_CPU 4000000UL; //Define F_CPU as 4MHz
int volatile randomnum; //Declare volatile variable for random number generation
int volatile speed; //Declare volatile variable to get the reaction speed
int main(void)
{
DDRB = DDRB | 0b00100111; //Configure PB5,PB0,PB1,PB2 as outputs
DDRD = DDRD & 0b11110011; //Configure PD2(INT0), PD3(INT3) as inputs
PORTD = PORTD | 0b00001100; //Pull-up PD2, PD3
EICRA = (EICRA & 0b11111010) | 0b00001010; //Set external interrupt on falling edge of INT0,INT1
EIMSK = EIMSK | 0b00000011; //Enable external interrupt on INT0,INT1
sei(); //Enable interrupts globally
TCCR1B = (TCCR1B & 0b11111101) | 0b00000101; //Set clock source as F_CPU/1024
TCNT1 = 0; //Default TCNT value as 0
while (1)
{
}
return 0;
}
ISR(INT0_vect){
time_t t; //Declare time variable
PORTB = 0; //Switch off all LEDs
srand( (unsigned) time(&t) ); //Seed the random number using time
randomnum = rand() % 10 + 1; //Generate a random number between 1-10
TCNT1 = ( 65535 - (randomnum * 3906.25) ) + 1; //Assign the value for TCNT to get the delay of random number seconds
TIMSK1 = TIMSK1 | 0b00000001; //Enable timer overflow interrupt
}
ISR(TIMER1_OVF_vect){ //ISR for timer overflow interrupt
PORTB=PORTB|0b00100000; //Switch ON LED connected to PB5
}
ISR(INT1_vect){
speed = TCNT1 / 3906.25; //Calculate the time taken to react
if(speed > 2) //If reaction time greater than 2s
{
PORTB = PORTB | 0b00000100; //Switch ON LED connected to PB2
}
else if ( (speed<2) && (speed>1) ) //If reaction time greater than 1s but less than 2s
{
PORTB = PORTB | 0b00000010; //Switch ON LED connected to PB1
}
else if(speed < 1) //If reaction time less than 1s
{
PORTB = PORTB | 0b00000001; //Switch ON LED connected to PB0
}
}
I have tried to find references on C programs to code embedded system as above. But failed as all those were in arduino.
The above program seems to work only if random number generates as 1. I couldn't find where is the error. Can you please refer my code and point me where the error is?
I think you should clear the overflow flag BEFORE enabling the related interrupt.
Otherwise, if the flag is already set (i.e. about 17 seconds have passed since starting up the program) the interrupt will fire right away.
Please try this, just before enabling the overflow interrupt:
TIFR1 = 0b00000001; // Clear timer overflow flag

Control motors' speed using C in Arduino results in different speed despite having the same value

I'm trying to using C on the Arduino board to control the speed of the 2 motors. However, when uploading the code, each motor runs at different speed despite having the same OCR value. Can you give it a check for the reasons, I would be very appreciate if you do so. The two motors is the same. The board I use is Arduino Uno
#include <avr/io.h>
#include <util/delay.h>
void setup() {
DDRB = B11111100;
DDRD = B00000000;
TCCR2A = TCCR1A = B10100011;
TCCR2B = B00000001;
TCCR1B = B00000100;
OCR2A = 0;
OCR1B = 0;
}
void loop() {
OCR1B = 255;
OCR2A = 255;
PORTB |= _BV(PORTB4);
PORTB |= _BV(PORTB5);
}
Timer 2 is 8 bit wide, but Timer 1 is 16 bit wide. The motor connected to the OCR1B output gets 255/65535=0.3% PWM, while OCR2A gives 255/255 = 100% PWM to the other motor.
You can
use the CTC (clear timer on compare match) mode
use two timers of the same width, like timer 0 and timer 2
use two output compare units of the same timer (e.g. OCR1A/OCR1B)

AVR timer overflow interrupt not working

Hello good people of stack overflow. My problem is an interrupt service routine (ISR) that seemingly never executes! Here's some info on my set up:
I am flashing an avr attiny85. I have the bare bones of a project set up so far with simply a main.c and two modules: timer and hardwareInit. In the timer module, I have a timer0_init function that I am using to set up timer0 for CTC mode to overflow ever 1 ms. Here is the function:
void timer0_init( void )
{
cli();
TCCR0B |= 3; //clock select is divided by 64.
TCCR0A |= 2; //sets mode to CTC
OCR0A = 0x7C; //sets TOP to 124 so the timer will overflow every 1 ms.
TIMSK |= 2; //Enable overflow interrupt
sei(); //enable global interrupts
}
with the timer set up, I added an ISR to increment ticks every time the counter overflows, so I can keep track of how much time has elapsed, etc.
ISR(TIMER0_OVF_vect)
{
cli();
//ticks ++;
PORTB |= ( 1 << PORTB0 );
sei();
}
as you can see, I commented out the ticks++ because it wasn't working, and replaced it with PORTB |= ( 1 << PORTB0 ); which simply turns on an LED, so if the interrupt is ever executed, I will know by proof of the LED being on.
Unfortunately, I can't get it to turn on and can't see what I'm missing. (to prove that I 1. have the LED set up on the right pin, and 2. am manipulating the correct bit in the correct register, I put just this statement PORTB |= ( 1 << PORTB0 ); in my infinite loop and confirmed the LED came on)
For further explanation, here is my main.c:
/*================================= main.c =================================*/
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "timer.h"
#include "hardwareInit.h"
int main(){
//Initialize hardware HERE
DDRB |= ( 1 << PORTB0 ); //set this pin as an output for an LED
SetClockPrescale(1); //internal clock divided by 1 = 8 MHz, from hardwareInit
timer0_init(); //set up timer0 for 1 ms overflow
while(1)
{
/* if( getTicks() > 0 )
{
PORTB |= ( 1 << PORTB0 );
_delay_ms(1000);
PORTB &= ~( 1 << PORTB0 );
_delay_ms(1000);
} */
}
return 0;
}
So, what you see in the infinite loop is what I tried first, but after that didn't work, I tried something simpler, just having an empty loop (commented out previous stuff), and waiting for the interrupt to get triggered which would turn on the LED.
Any help you could give would be really appreciated. I'm quite puzzled why this hasn't been working.
You are using the wrong ISR as #andars has pointed out correctly. In CTC "Clear Timer on Compare" mode the timer will never overflow as it will be cleared on compare match.
So you enabled the wrong interrupt of the timer as well. Bit 1 of TIMSK register enables timer overflow interrupt on timer0. That won't be triggered because of the previous reason. Taken from datasheet.
As you are using OCR0A to set the compare value, you have to enable Bit 4 – OCIE0A: Timer/Counter0 Output Compare Match A Interrupt Enable.
Back to the ISR, you need the ISR(TIMER1_COMPA_vect) or ISR(TIMER1_COMPB_vect) depending on which bit you set in TIMSK. Note that the compare value should be written into the matching registers as well, OCR0A or OCR0B.
Note that, you can use the bit names in your code just like the register names, in my opinion it makes the code more transparent.
Your code should be changed as follows to enable the corresponding interrupt:
void timer0_init( void )
{
cli();
TCCR0B |= (1<<CS01) | (1<<CS00); //clock select is divided by 64.
TCCR0A |= (1<<WGM01); //sets mode to CTC
OCR0A = 0x7C; //sets TOP to 124 so the timer will overflow every 1 ms.
TIMSK |= (1<<OCIE0A); //Output Compare Match A Interrupt Enable
sei(); //enable global interrupts
}
The ISR:
ISR(TIMER0_COMPA_vect)
{
cli();
//ticks ++;
PORTB |= ( 1 << PORTB0 );
sei();
}

Resources