issue in counting down timer from 60 to 0 on 7segment - c

/*
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.

Related

Controller received data whilst busy

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.

Code for 4-Digit 7-Segment Display: Why doesn't code work for 2 of 4 digits?

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
}

Custom Delay function using arduino IDE

I'm in a microprocessors class and we're writing our own delay functions that are actually accurate. Our professor gave us, what I assume is, a 4 ms delay function. I don't really understand how to transfer that to a .25 s or a 1 s delay, which are both needed for my homework.
The given function is as follows(Assume _BV() is defined as _BV(x) 1<<(x)):
DDRB |= _BV(1);
TCCR1A |= _BV(COM1A0);
TCNT1 = 0;
OCR1A = 100;
TIFR1 = _BV(OCF1A);
TCCR1B |= _BV(CS10);
while((TIFR1 & _BV(OCF1A)) == 0);
TIFR1 = _BV(OCF1A);
OCR1A = 100 + 64000;
while((TIFR1 & _BV(OCF1A)) == 0);
TCCR1B = 0;
TCCR1A = 0;
I've written the code needed to complete the homework except the two delay functions.
Here is what I have so far:
#include <avr/io.h>
uint8_t numIN;
void setup() {
Serial.begin(9600);
DDRB |= _BV(5);
}
void loop() {
int i;
numIN = 10;
Serial.println("Enter a number between 0 and 9.");
do {
while (Serial.available() > 0)
{
numIN = Serial.read() - '0';
if (numIN < 0 || numIN > 9)
{
Serial.println("Input Error!");
}
}
} while (numIN < 0 || numIN > 9);
Serial.print("You entered ");
Serial.println(numIN);
if (isEven(numIN))
{
for (i = 0; i < 5; i++)
{
PORTB |= _BV(5);
delay(1000); //temporary
//delay_Sec();
PORTB &= ~_BV(5);
delay(1000); //temporary
//delay_Sec();
}
}
else
{
for (i = 0; i < 5; i++)
{
PORTB |= _BV(5);
delay(250); //temporary
//delay_quarterSec();
PORTB &= ~_BV(5);
delay(250); //temporary
//delay_quarterSec();
}
}
}
void delay_quarterSec(void)
{
//need to finish
}
void delay_Sec(void)
{
//need to finish
}
boolean isEven(int num)
{
if (num & _BV(0))
return false;
else
return true;
}
I'm just confused how I take my professor's code and transfer it to what I need to do. Any help is greatly appreciated!
I can give you a quick overview about what the provided code does.
(This is from memory, so don't take my word for it. And you don't mention your controller type. You will have to look up the registers up in detail.)
DDRB |= _BV(1); // set the compare match output pin to output
TCCR1A |= _BV(COM1A0); // enable output compare PIN toggle
TCNT1 = 0; // set counter start value to 0
OCR1A = 100; // set compare match value to 100 (the actual delay)
TIFR1 = _BV(OCF1A); // clear the output compare flag
TCCR1B |= _BV(CS10); // enable the timer by setting the pre-scaler
while((TIFR1 & _BV(OCF1A)) == 0); // wait until the timer counted to 100 (compare flag is set again)
So the actual delay depends on:
the setting of the prescaler
the clock speed of your controller
the value of OCR1A
Example:
If the prescaler is set to 1 and you run at 10MHz you got
t = (1 / (10000000/s)) * 100 = 10us
This should get you started.

is it possible compare a 16-bit value with a 8-bit compare match ISR

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();
}
}

Longer Time Delay When More Then One "while" Polling Instruction

Microcontroller : ATmega328P in Arduino Uno
Clock Frequency : 16MHz
void timeDelay_CTC(float sec, unsigned char times) //0.1 <= sec <= 4
{
OCR1A = (sec / 0.000064f) - 1;
TCCR1A = 0b00000000;
TCCR1B = 0b00001101;
for( unsigned char i = 1; i <= times; i++ )
{
while( (TIFR1 & (1<<OCF1A)) == 0 );
TIFR1 |= (1<<OCF1A);
}
TCCR1A = 0;
TCCR1B = 0;
}
The above function is used for calculating the number of time delay cycles and then implement it in CTC mode. It works well. Now, I want to write a similar function in normal mode. The folowing is the code.
void timeDelay_NORM(float sec, unsigned char times)
{
unsigned int cycle = (sec / 0.000064f);
TCNT1 = 65534 - cycle;
TCNT1 = 49910;
TCCR1A = 0b00000000;
TCCR1B = 0b00000101;
for( unsigned char x = 1; x <= 2; x++ )
{
while( (TIFR1 & (1<<TOV1)) == 0 );
TIFR1 |= (1<<TOV1);
}
TCCR1A = 0;
TCCR1B = 0;
}
However, the normal mode function with argument "times" > 1, the time delay will be much longer than expected. So, I tried the following code.
void timeDelay_NORM(float sec, unsigned char times)
{
//unsigned int cycle = (sec / 0.000064f);
//TCNT1 = 65534 - cycle;
TCNT1 = 49910; //Cycles for 0.5sec
TCCR1A = 0b00000000;
TCCR1B = 0b00000101;
//for( unsigned char x = 1; x <= 2; x++ )
//{
while( (TIFR1 & (1<<TOV1)) == 0 ); //Run 0.5sec two times to delay 1sec
TIFR1 |= (1<<TOV1);
while( (TIFR1 & (1<<TOV1)) == 0 );
TIFR1 |= (1<<TOV1);
//}
TCCR1A = 0;
TCCR1B = 0;
}
I found that when it run the following instruction 2 times, the time delay will be much longer than expected. It delay around 5s instead of 1s.
while( (TIFR1 & (1<<TOV1)) == 0 );
TIFR1 |= (1<<TOV1);
Can you teach me how to make it work? Or give me some hints.
Thank you for your help!
You do not reset TCNT1 between the loop iterations.
On the first loop it will count (UINT16_MAX - 49910) cycles. After TOV1 is set, TCNT1 rolls over to 0 (overflow) and counts up all the way to UINT16_MAX which causes the longer delay.

Resources