I am trying to use interrupts in code vision for proteus. INT0 for increasing the counter value and INT1 for decreasing it. for that purpose I declared two funcions interrupt [EXT_INT0] void ext_int0_isr(void) and interrupt [EXT_INT1] void ext_int1_isr(void) but when I run the code it doesn't work and I get the infinite warning "Controller received data whilst busy" in proteus. I'd really appreciate if you could help me.
#include <mega8535.h>
#include <alcd.h>
#include <stdio.h>
#include <delay.h>
int i = 0 ;
int j = 0 ;
char number[16];
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
#asm("cli")// Global disable interrupts
i++;
//go to products counting
if(i < 10) goto ENTERED;
//go to products packaging process
if(i >= 11)
{
lcd_clear();
lcd_gotoxy(2,0);
lcd_putsf("Products Are");
for (j=0; j < 10; j++)
{
lcd_gotoxy(1,1);
lcd_putsf("Being Packaged.");
delay_ms(500);
lcd_gotoxy(1,1);
lcd_putsf("Being ");
delay_ms(500);
}
}
i=1;
ENTERED:
if(i < 11)
{
sprintf(number,"Number Of People=%d \n (one Entered)",i);
}
}
// External Interrupt 1 service routine
interrupt [EXT_INT1] void ext_int1_isr(void)
{
#asm("cli")// Global disable interrupts
i--;
//go to products counting
if(i < 11) goto WENTOUT;
//go to products packaging process
if(i >= 11)
{
lcd_clear();
lcd_gotoxy(2,0);
lcd_putsf("Products Are");
for (j=0; j < 10; j++)
{
lcd_gotoxy(1,1);
lcd_putsf("Being Packaged.");
delay_ms(500);
lcd_gotoxy(1,1);
lcd_putsf("Being ");
delay_ms(500);
}
}
i=1;
WENTOUT:
if(i < 11)
{
sprintf(number,"Number Of People=%d \n (one went out)",i);
}
}
void main(void)
{
// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Falling Edge
GICR|=(1<<INT1) | (1<<INT0) | (0<<INT2);
MCUCR=(1<<ISC11) | (0<<ISC10) | (1<<ISC01) | (0<<ISC00);
MCUCSR=(0<<ISC2);
GIFR=(1<<INTF1) | (1<<INTF0) | (0<<INTF2);
// Alphanumeric LCD initialization
// Connections are specified in the
// Project|Configure|C Compiler|Libraries|Alphanumeric LCD menu:
// RS - PORTA Bit 0
// RD - PORTA Bit 1
// EN - PORTA Bit 2
// D4 - PORTA Bit 4
// D5 - PORTA Bit 5
// D6 - PORTA Bit 6
// D7 - PORTA Bit 7
// Characters/line: 16
lcd_init(16);
sprintf(number,"Number Of People=%d",i);
while (1)
{
lcd_gotoxy(4,0);
lcd_puts(number);
#asm("sei")// Global enable interrupts
delay_ms(50);
lcd_clear();
}
}
The problem was that the string's length that I was trying to put in the LCD was more than LCD's capacity and after I shortened the string the problem was solved.
Related
/*
T=1/8MHz=0.125us
0>>>256=32us time for 1 clock
1/32*(10^-6)
so we need 31250 clock to generate 1 sec
for prescaling 256 we need 123 clock
*/
/*
123 CLOCK FOR 1 SEC
SO 1230 CLOCK FOR 10 SEC
*/
#define F_CPU 8000000UL
#include <avr/io.h>
void T0delay()
{
TCNT0 = 0;
TCCR0 = 0x04;
while (TIFR & (1<<TOV0)==0);
TCNT0 = 0;
TIFR =0x01;
}
int main(void)
{
int counter=0;
int i=0;
int j=6;
DDRC=0xff;
DDRD=0xff;
PORTC=i;
PORTD=j;
while (1)
{
T0delay();
counter++ ;
if(counter == 123)
{
i--;
if(i < 0)
{
i = 9;
PORTD--;
if(PORTD == 0 & PORTC == 0 )
{
PORTD =0;
PORTC =0;
}
}
PORTC=i;
}
}
}
Port c for stepping down timer from 9 to 0 count each sec.
Behavior is not accurate as it doesn't wait whole second.
While port d for stepping down timer from 6 to 0 count each cycle (9 to 0 ) of the port c 7segment.
The behavior is not right as it counts from 6 to 0 then it displays unwanted segments.
Schematics
To solve your problem, you need to analyze the different cases for the values that you are branching on (if statements) and how you are treating their values.
First off, PORTD and PORTC are GPIO registers which means their values are unsigned so I believe the problem with your code is right here:
PORTD--;
if(PORTD == 0 & PORTC == 0 )
{
PORTD =0;
PORTC =0;
}
When the if(PORTD == 0 & PORTC == 0 ) branch is taken, PORTD is set to 0. The next time if(i < 0) is taken PORTD is then decremented which causes overflow, giving you the unwanted behavior you are experiencing.
I have written 2 functions (gpio_write & gpio_set_function) to be able to control the digits and segments of a 7-Segment Display (Common Anode LED), that is connected to my RPi via Bipolar Junction Transistors: Collector to common power, base to RPi pins via 1 kOhm resistor, and emitter to digit nodes on the display (image here).
The segments are connected directly to pins on the RPi.
The code successfully lights up digits 1 & 3, (and all segments) but digits 2 and 4 do not light up. I need some help figuring out why that is.
I have double & triple checked the wiring, made sure the digits are connected to pins 10 thru 13, and the segments to pins 20 thru 26 (period to pin 27). I have checked the code as well, and couldn't find a problem with it. I have also made sure that each of the digits actually works by disconnecting from the RPi and lighting up each of the segments on each digit independently (Segment B of Digit 3 is burned, all the others work).
What could be another issue that would cause digits 2 and 4 not to light up? Or perhaps something IS wrong with the code?
#include "timer.h"
#include "gpio.h"
void gpio_set_function(unsigned int pin, unsigned int function) {
unsigned int mask = 7;
if ( (pin < GPIO_PIN_FIRST || pin > GPIO_PIN_LAST) || (function < GPIO_FUNC_INPUT || function > GPIO_FUNC_ALT3) )
;
else{
switch (pin/10){
case 0:
*GP_FSEL0 &= ~((mask)<<(3*pin));
*GP_FSEL0 |= function<<(3*pin);
break;
case 1:
pin = pin%10;
*GP_FSEL1 &= ~((mask)<<(3*pin));
*GP_FSEL1 |= function<<(3*pin);
break;
case 2:
pin = pin%20;
*GP_FSEL2 &= ~((mask)<<(3*pin));
*GP_FSEL2 |= (function<<(3*pin));
break;
case 3:
pin = pin%30;
*GP_FSEL3 &= ~((mask)<<(3*pin));
*GP_FSEL3 |= function<<(3*pin);
break;
case 4:
pin = pin%40;
*GP_FSEL4 &= ~((mask)<<(3*pin));
*GP_FSEL4 |= function<<(3*pin);
break;
default:
;
}
}
}
void gpio_write(unsigned int pin, unsigned int value) {
if ( (pin < GPIO_PIN_FIRST || pin > GPIO_PIN_LAST) || (value < 0 || value > 1) ) ;
else {
switch (pin/32){
case 0:
if (value==1){
*GP_FSET0 &= ~(1<<pin);
*GP_FSET0 |= 1<<pin;
}
else
*GP_CLR0 |= 1<<pin;
break;
case 1:
if (value==1){
*GP_FSET1 &= ~(1<<(pin-32));
*GP_FSET1 |= 1<<(pin-32);
}
else
*GP_CLR1 |= 1<<(pin-32);
break;
default:
;
}
}
}
void main(void) {
volatile int i;
for(i = 10; i < 14 ; i++)
gpio_set_function(i, GPIO_FUNC_OUTPUT);
for(i = 19; i < 27 ; i++)
gpio_set_function(i, GPIO_FUNC_OUTPUT);
while (1){
for(i = 10; i < 14 ; i++)
gpio_write(i, 1);
for(i = 19; i < 27; i++)
gpio_write(i, 0);
for (volatile int delay = 0xF0000; delay != 0; delay--);
for(i = 10; i < 14 ; i++)
gpio_write(i, 0);
for (volatile int delay = 0x0000F; delay != 0; delay--);
}
}
ADDITIONAL ATTEMPT:
I tried simplifying the code by not using any functions. Still getting the same result. All segments work on digits 1 and 3. Digits 2 and 4 do not light up.
void main(void) {
// set functions
unsigned int mask = 7;
*GP_FSEL1 &= ~((mask)<<(3*1)); // reset pin 11
*GP_FSEL1 |= GPIO_FUNC_OUTPUT<<(3*1); // set pin 11 to OUTPUT
*GP_FSEL2 &= ~((mask)<<(3*0)); // reset pin 20
*GP_FSEL2 |= GPIO_FUNC_OUTPUT<<(3*0); // set pin 20 to OUTPUT
*GP_FSET0 &= ~(1<<11); // reset SET Reg of pin 11
*GP_FSET0 |= 1<<11; // set SET Reg of pin 11 to high
*GP_CLR0 &= ~(1<<20); // reset CLR Reg of pin 20
*GP_CLR0 |= 1<<20; // set CLR Reg of pin 20 to high
}
I am interfacing LM35 with Atmega8. To display digits I use 7 segment LED anode display that I connect to AVR both ends (it handles it without transistors so why not). Strange thing happens:
res value after assigning it from adc is 237 (23.7 degrees). I want to print on my display the first digit (2).
If I leave last line in the while commented out, the display first shows digit 2 correctly but after the first delay it shows 1 instead of 2. Otherwise I get correctly digit 2. Why is this happening?
#ifndef F_CPU
#define F_CPU 1000000UL
#endif // F_CPU
#include <avr/io.h>
#include <util/delay.h>
#define DELAY_IN_MS 500 /* 0.5 sec */
int numbers[] = {
0b01000000,
0b01110011,
0b00100100,
0b00100001,
0b00010011,
0b00001001,
0b00001000,
0b01100011,
0b00000000,
0b00000001,
0b11111111 // off
};
uint8_t digits[3];
void initADC()
{
ADMUX=(1<<REFS1)|(1<<REFS0);
ADCSRA=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}
uint16_t ReadADC(uint8_t ch)
{
//Select ADC Channel ch must be 0-7
ch=ch&0b00000111;
ADMUX|=ch;
//Start Single conversion
ADCSRA|=(1<<ADSC);
//Wait for conversion to complete
while(!(ADCSRA & (1<<ADIF)));
//Clear ADIF by writing one to it
ADCSRA|=(1<<ADIF);
return(ADC);
}
int main()
{
DDRD = 0xFF;
PORTD = 0xFF;
DDRB = 0b00000001;
PORTB = 1;
initADC();
uint16_t adc_value;
uint16_t res;
while(1)
{
adc_value = 0;
for (int i = 0; i < 250; i++)
{
adc_value += ReadADC(0);
}
adc_value=(adc_value/25)/4;
res = adc_value;
for(int j = 2; j >= 0; j--) {
digits[j] = res%10;
res /= 10;
}
uint8_t dig = digits[0];
PORTD = numbers[dig];
_delay_ms(DELAY_IN_MS);
// if following is uncommented there blinks digit two correctly
// if commented there is unblinking digit 1
PORTD = numbers[10]; // display off
}
return 0;
}
The problem was induction.
My circuit had many wires in non-soldering-field. When the display was on, there was a lot of induction going on changing resulting voltage on ADC input/LM35 output.
There is more than one solution.
1) Software: I moved ADC conversion into the interruption function. It turns of the displays, converts value from lm35 and displays digit on proper display. It happens so fast that the eye cant perceive it.
I prefer this one for now, because it makes my circuit simpler.
2) Hardware: adding L/C or R/C filter to adc pin should resolve the issue.
Full code for 1)
#ifndef F_CPU
#define F_CPU 1000000UL
#endif // F_CPU
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define DELAY_IN_MS 5000 /* ms */
#define NUM_OF_MEASUREMENTS 100
#define NUM_DISPLAYS 3
int numbers[] = {
0b10000001,
0b10011111,
0b10100100,
0b10010100,
0b10011010,
0b11010000,
0b11000000,
0b10011101,
0b10000000,
0b10010000,
0b11111111 // off
};
int display = 0;
uint8_t digits[NUM_DISPLAYS];
volatile uint16_t adc_values[NUM_OF_MEASUREMENTS];
int adc_read_cycle_index = 0;
uint32_t res;
void initADC()
{
ADMUX=(1<<REFS1)|(1<<REFS0);
ADCSRA=(1<<ADEN)|(1<<ADPS2);
}
uint16_t ReadADC(uint8_t ch)
{
//Select ADC Channel ch must be 0-7
ch=ch&0b00000111;
ADMUX|=ch;
//Start Single conversion
ADCSRA|=(1<<ADSC);
//Wait for conversion to complete
while (ADCSRA & (1<<ADSC));
return(ADC);
}
void readDegrees()
{
adc_values[adc_read_cycle_index] = (ReadADC(0)*10)/4;
if(adc_read_cycle_index + 1 == NUM_OF_MEASUREMENTS) {
adc_read_cycle_index = 0;
} else {
adc_read_cycle_index++;
}
}
void fetchTemperatureDigits() {
res = 0;
for(int i = 0; i < NUM_OF_MEASUREMENTS; i++) {
res += adc_values[i];
}
res /= NUM_OF_MEASUREMENTS;
for(int j = 2; j >= 0; j--) {
digits[j] = res%10;
res = res / 10;
}
}
void initTimer0()
{
// Prescaler = FCPU/64
TCCR0|=(1<<CS01);//|(1<<CS00);
//Enable Overflow Interrupt Enable
TIMSK|=(1<<TOIE0);
//Initialize Counter
TCNT0=0;
}
ISR(TIMER0_OVF_vect)
{
// turn off displays
PORTD = numbers[10];
// read ADC and convert to degrees
readDegrees();
// turn on proper anode
PORTB &= 0b11111000;
PORTB |= (1<<display);
// show digit
PORTD = numbers[digits[display]];
// show decimal point for second display (21.5 - second display shows "1.")
if(display == 1) {
PORTD &= 0b01111111;
}
// next display for next interruption
display++;
if(display == NUM_DISPLAYS) {
display = 0;
}
}
int main()
{
initADC();
for(int i = 0; i < NUM_OF_MEASUREMENTS; i++) {
readDegrees();
}
DDRD = 0xFF;
PORTD = 0;
DDRB |= 0b00000111;
PORTB |= 1;
initTimer0();
sei();
while(1) {
fetchTemperatureDigits();
_delay_ms(DELAY_IN_MS);
}
return 0;
}
I am trying to create a code that takes in an input from a 4x3 keypad, then turns that input into a duty cycle which using the Timer_A will adjust the LED's intensity. However my code is not working and I was wondering what changes the code needs. The code successfully prints the J value in setLED but it has no effect on the LED. I have also successfully tested the Timer_A by itself to make sure the circuit is wired correctly. Thanks
#include "msp.h"
#include < stdio.h >
uint8_t Read_Keypad(); //Reads keypad
void InitKeypad(); //GPIO initialization of keypad
void InitTimer();
void printKey(); //Print the pressed key
void SaveInput(); //Stores the pressed number
void setDutyCylce(); //Converts an integer to a string character
void setLED();
uint32_t num;
uint8_t i = 0, k = 0;
float dCycle, period = 3000-1, j = 0.0, tempDC;
int a1[3];
int main(){
WDT_A->CTL = WDT_A_CTL_PW | // Halts Watch dog
WDT_A_CTL_HOLD;
uint8_t pressed = 0;
InitKeypad();
InitTimer();
printf("\nPlease enter a duty cycle.\n\n"); //Request keypad entry
while(1){ //Loop used to run through the keypad sequencing indefinitely
pressed = Read_Keypad(); // Calls Function that reads Keypad
if(pressed){ // If a button is pressed this will be true
printKey(); // Call print key to display the pressed key
SaveInput(); // Call SaveInput Store the acsii value into a character array
setDutyCylce(); // Used to convert an integer to a string character
setLED();
__delay_cycles(30000); // delay for 10ms each time through the loop before reading keypad //again
}
}
}
void InitKeypad(){
//Sets the whole P4 register as GPIO
P4SEL0 &=~0xFF; P4SEL1 &=~0XFF;
// Set Keypad Row0 to P4.0 Row1 to P4.1 Row2 to P4.2 Row3 to P4.3
P4->DIR &=~ (BIT0 | BIT1 | BIT2 | BIT3);
// Enable pull-up resistor on all rows P4.0, P4.1, P4.2, P4.3
P4REN |= (BIT0 | BIT1 | BIT2 | BIT3);
// Configure rows with pull-up rows P4.0, P4.1, P4.2, P4.3
P4OUT |= (BIT0 | BIT1 | BIT2 | BIT3);
// Set Keypad Columns to Inputs P4.6 Col_1 P4.5 Keypad Col_0 P4.4
P4->DIR &=~(BIT4 | BIT5 | BIT6);
}
void InitTimer(){
P2->DIR |= BIT4; // P2.4 set TA0.1 P2->SEL0 |= BIT4;
P2->SEL0 |= BIT4;
P2->SEL1 &= ~(BIT4);
TIMER_A0->CCR[0] = period; // PWM Period (# cycles of the clock)
TIMER_A0->CCTL[1] = TIMER_A_CCTLN_OUTMOD_7;
TIMER_A0->CCR[1] = dCycle; // CCR1 PWM duty cycle in 10ths of percent
TIMER_A0->CTL = TIMER_A_CTL_SSEL__SMCLK | TIMER_A_CTL_MC__UP | TIMER_A_CTL_CLR;
}
uint8_t Read_Keypad(){
uint8_t col,row;
for(col=0; col<3; col++){
P4->DIR = 0x00; // Set Columns to inputs
P4->DIR |= BIT(4 + col); // Set Column 3 to Output
P4->OUT &=~ BIT(4 + col); // Set Column 3 to LOW
__delay_cycles(10); // Delay the while loop
row = P4->IN & 0x0F; // Read all rows
while(!(P4IN & BIT0)| !(P4IN & BIT1)| !(P4IN & BIT2) | !(P4IN & BIT3));
if(row != 0x0F){ // If one of the inputs is low, some key is pressed.
break; // Breaks out of the for loop
}
}
P4->DIR |= 0x00; // Set Columns to inputs
if (col == 3) return 0; // No button is was pressed during this iteration
if (row == 0x0E) num = (col + 1); // Key in row 0
if (row == 0x0D) num = (3 + col + 1); // Key in row 1
if (row == 0x0B) num = (6 + col + 1); // Key in row 2
if (row == 0x07) num = (9 + col + 1); // Key in row 3
return 1;
}
void printKey(){
if (num == 10) printf(" *\n"); // If the number is 10 the value is *
if (num == 12) printf(" #\n"); // If the number is 12 the value is #
if (num == 11){
printf(" 0\n"); // If the number is 11 the value is 0
num = 0;
}
if (num < 10) printf(" %d\n",num); // If any other number is pressed the value is the number
}
void SaveInput(){
if(!(num == 10 || num == 12)){ // Prevent the characters * and # from being stored
a1[0] = a1[1]; // Value at index 0 will be overwritten and go away
a1[1] = a1[2]; // Shift all index values to the left
a1[2] = num; // The newest value to be stored
i++; // Used to ensure 4 number have been entered
}
}
void setDutyCylce(){ //converts input to a percentage, then pwm cycle
if(i >= 1 && num == 12){
tempDC = a1[0];
tempDC = (tempDC * 10) + a1[1] ;
j = (tempDC * 10) + a1[2];
tempDC = (j/100);
dCycle = (tempDC * period);
a1[0] = 0;
a1[1] = 0;
a1[2] = 0;
}
}
void setLED(){
if(i >= 1 && num == 12 && j <= 100){
P2->OUT |= BIT4; //turns ON
printf("LED now operating with %.1f power.\n", j);
i=0;
}
if(i >= 1 && num == 12 && j > 100){
printf("\n Invalid duty cycle.\n", j);
P2->OUT &=~ BIT4; //turns OFF
i=0;
}
}
I definately need more information here about hardware.
At a glance, I will say you are changing dCycle in setDutyCycle but only ever using dCycle in InitTimer which is only called once.
After initializing the pwm duty cycle to a dCycle that was declared once, do you mean to change again and again through while loop?
I am trying to make a servo controller that have a higher resolution than the ATtiny85 8-bit timer/counter. So far I have managed to get about 2000 positions on my servo (1µs/step) within a time frame of 21'000 µs. I have also managed to move 5 servos sequential and with different speed, but now I want to move them synchronous.
My biggest problem is that I don't get how I should make it happen! I have looked around on other servo codes including servo8bit library and tried to find a way. It seems that most of the examples uses compare match ISR to move the servos "at the same time", my problem is that I have a 16-bit integer that I want to compare.
Is there a way to do some magic so I can use the 8-bit compare match ISR with my 16-bit integer? Or does anyone of you have some other suggestions on how I can move my servos synchronous without using compare match ISR?
I hope my questions make sense!
Since I don't really have any code to show yet (only flawed attempts without compar match ISR that makes no sense) I post the link to my TinyServo code if it helps.
EDIT 1:
Here is the part of the code I mentioned and didn't post the first time:
void servoMove(void)
{
uint16_t nextPulse = hPulse[0];
timerSetup (); //16-bit setup for counter
for (i = 0; i < sizeof(servo)/sizeof(servo[0]); i++)
{
if ( (oTime > nextPulse) && (channel < sizeof(servo)/sizeof(servo[0])) ) //check if HIGH pulse (pos) is done
{
PORTB &= ~(1 << servo[channel]);
if (i+1 < sizeof(hPulse)/sizeof(hPulse[0]))
{
nextPulse += hPulse[i+1];
}
channel++;
}
else
{
channel = 0;
oTime = 0; //resets 16-bit variable
tot_overflow = 0; //resets tot_overflow variable
TIFR |= (1 << TOV1); // clear counter1 overflow-flag
TCNT1 = 0; //resets Timer/Counter1
}
}
for (i = 0; i < sizeof(servo)/sizeof(servo[0]); i++)
{
if ( (oTime > tPulse - nextPulse) && (channel < sizeof(servo)/sizeof(servo[0])) ) //check if LOW pulse (period) is done
{
PORTB |= (1 << servo[channel]);
nextPulse -= hPulse[i];
channel++;
}
}
}
void servoPosSet(volatile uint16_t pos[], uint8_t size)
{
for (i = 0; i < size; i++)
{
hPulse[i] = pos[i];
}
}
int main(void)
{
TCCR1 |= (1 << CS12); //set Timer/Counter1 prescaler to increment every 1 µs (PCK/8)
for (channel = 0; channel < size); channel++)
{
DDRB |= (1 << servo[channel]); //sets PB0-PB4 as output pins
}
channel = 0;
uint16_t pos[] = {2000, 1500, 1900, 1300, 1700};
uint8_t size = 5;
while(1)
{
servoPosSet(pos);
servoMove();
}
}
EDIT 2:
This is an illustration of how I think the code should work:
...but it does not!
If you have nothing else to do during the pulse, you could use a busy
loop instead of interrupts:
#include <avr/io.h>
#include <util/delay_basic.h>
/* Send a pulse of width = 4*count cycles. */
void pulse(uint16_t count, uint8_t channel)
{
uint8_t mask = 1 << channel,
old_port = PORTB,
high = old_port | mask,
low = old_port & ~mask;
PORTB = high;
_delay_loop_2(count);
PORTB = low;
}
This will give you a resolution of 4 clock cycles, or 0.5 µs with a
8 MHz clock.
Sending the pulses to the 5 servos should take at most 10 ms. Since
you repeat the pulse train every 21 ms, this leaves you 11 ms
to compute the next set of positions, which should be plenty. You could
program a timer to wake you up every 21 ms, then your main() may
look like:
int main(void)
{
static uint16_t pos[] = {4000, 3000, 3800, 2600, 3400};
uint8_t i;
/* Wake up every 21 ms. */
setup_timer();
sleep_enable();
for (;;) {
/* Update the servos. */
for (i = 0; i < 5; i++) pulse(pos[i], i);
/* Compute the next set of positions. */
...
/* Wait for timer interrupt. */
sleep_cpu();
}
}