Interfacing a 4x4 keypad matrix with Atmega32 - c

I am trying to interface an Atmega32 micro-controller with a 16x2 LCD and a 4x4 keypad matrix. I am simulating with Proteus and using WinAVR compiler.
The LCD part is okay (I have thoroughly tested it). The keypad code, however, is not running as I expect. Whenever I press a key, the scanning of keypad rows stops indefinitely.
Also the key doesn't display on the LCD. Please help me find the bug.
Below is the circuit schematic as drawn in Proteus, as well as the code. I have not included code for the LCD here since I know that part is working perfectly well.
Circuit:
Code:
#include <avr/io.h>
#include<util/delay.h>
//Keypad Information
#define R0 0
#define R1 1
#define R2 2
#define R3 3
#define C0 4
#define C1 5
#define C2 6
#define C3 7
#define keypadPORT PORTA
#define keypadPIN PINA
#define keypadDDR DDRA
//Keypad functions and global variables
char getkey();
int keypadRow[] = {R0, R1, R2, R3}; //rows of the keypad
int keypadCol[] = {C0, C1, C2, C3};//columnd
int main()
{
char key_pressed;
keypadDDR |= (1<<R0)|(1<<R1)|(1<<R2)|(1<<R3);//set upper part of keypad port as output
//this will be required for scanning the rows
keypadDDR &= ~((1<<C0)|(1<<C1)|(1<<C2)|(1<<C3));//set lower part of keypad port as input.This is
//the part of the keypad port where the rows are connected.
LCD_init(); //initialize LCD
while(1)
{
key_pressed = getkey();
switch(key_pressed)
{
case('A'):
break;//do nothing if no key is pressed
default:
send_char(key_pressed);//send the key pressed to LCD
}
}
return 0;
}
char getkey()
{
int i, j;
for(i = 0; i < 4; i++)
{
keypadPORT = 0x00;
keypadPORT |= (1 << keypadRow[i]);//send a high to a particular row of the keypad
for(j = 0; j < 4; j++)
{
if(bit_is_set(keypadPIN,keypadCol[j]))//check if key is pressed
{
while(bit_is_set(keypadPIN,keypadCol[j])); //wait for key to be released
switch(i)
{
case(0):
{
if (j == 0) return '7';
else if (j == 1) return '8';
else if (j == 2) return '9';
else if (j == 3) return '/';
break;
}
case(1):
{
if (j == 0) return '4';
else if (j == 1) return '5';
else if (j == 2) return '6';
else if (j == 3) return '*';
break;
}
case(2):
{
if (j == 0) return '1';
else if (j == 1) return '2';
else if (j == 2) return '3';
else if (j == 3) return '-';
break;
}
case(3):
{
if (j == 0) return '?';
else if (j == 1) return '0';
else if (j == 2) return '=';
else if (j == 3) return '+';
break;
}
}
}
}
}
return 'A';//Return 'A' if no key is pressed.
}

If, whenever you press a key, "the scanning of keypad rows stops indefinitely" and "the key doesn't display on the LCD", then I'd be looking at any potential infinite loops, such as the following line:
while(bit_is_set(keypadPIN,keypadCol[j]));
I don't know whether the columns drain away to ground or stay high when you release the key but you should be able to check that behaviour by replacing that line with:
send_char('<');
while(bit_is_set(keypadPIN,keypadCol[j]));
send_char('>');
If you are indeed getting caught in an infinite loop there, the display should show you the <.

Related

optimization code - 2D-array indexing in c

I read data from 2D-array buffer and write data to lcd using the 2-index row index and column index how to optimization this two byte (gu8LcdBufferColumn, gu8LcdBufferRow) to (single byte) in which the last 2-bit as a row index and first the 6 bit as column index.
two case the LCD_UPDATE_WRITE is write data into lcd and LCD_UPDATE_POS update the line of lcd
case LCD_UPDATE_WRITE:
if (gu8LcdBufferColumn != LCD_NUMBER_OF_BYTE) {
lcdWriteByte(gu8LCDBuffer[gu8LcdBufferRow][gu8LcdBufferColumn]);
gu8LcdBufferColumn++;
} else {
gu8LcdBufferColumn = 0;
gu8LcdBufferRow++;
if (gu8LcdBufferRow == LCD_NUMBER_OF_LINES) {
gu8LcdBufferRow = 0;
genLCDUpdateState = LCD_UPDATE_CHECK;
return (LCD_OK);
} else {
genLCDUpdateState = LCD_UPDATE_POS;
}
}
break;
case LCD_UPDATE_POS:
digitalPinWrite(LCD_RS, GPIO_LOW);
if (gu8LcdBufferRow == 0) {
lcdWriteByte(LCD_LINE_ONE_START);
} else if (gu8LcdBufferRow == 1) {
lcdWriteByte(LCD_LINE_TWO_START);
} else if (gu8LcdBufferRow == 2) {
lcdWriteByte(LCD_LINE_THREE_START);
} else if (gu8LcdBufferRow == 3) {
lcdWriteByte(LCD_LINE_FOUR_START);
}
digitalPinWrite(LCD_RS, GPIO_HIGH);
genLCDUpdateState = LCD_UPDATE_WRITE;
break;
last edit of this code with sync task two write data into lcd from buffer the macros lcd_line0_start and others is a hardware address in lcd convert this code to async task using switch case and write byte in each loop
case LCD_UPDATE_WRITE:
u8odd = 0;
u8even = 0;
if (bitIsClear(gu8LcdOPtion, LCD_DISPLAY)) {
/*the display on write command*/
digitalPinWrite(LCD_RS, GPIO_LOW);
/*set the display on*/
lcdWriteByte(LCD_DISPLAY_ON_COMMAND);
digitalPinWrite(LCD_RS, GPIO_HIGH);
genLCDUpdateState = LCD_UPDATE_CHECK; /*default state*/
return (LCD_OK);
}
for (uint8_t i = 0; i < LCD_NUMBER_OF_LINES; i++) {
digitalPinWrite(LCD_RS, GPIO_LOW);
if (i % 2 == 0) {
/*the number is even the start is 0x00 and D7 equal 1 = 0x80*/
/*line 0 and line 2*/
lcdWriteByte(LCD_LINE0_START + u8even);
u8even = LCD_NUMBER_OF_BYTE;
} else {
/*the number is odd*/
/*line 1 and line 3*/
/*the start is 0x40 and D7 = 1 a value is 0xc0*/
lcdWriteByte(LCD_LINE1_START + u8odd);
u8odd = (LCD_NUMBER_OF_BYTE);
}
digitalPinWrite(LCD_RS, GPIO_HIGH);
for (int j = 0; j < LCD_NUMBER_OF_BYTE; j++) {
lcdWriteByte(gu8LCDBuffer[i][j]);
}
}
/*the display on write command*/
digitalPinWrite(LCD_RS, GPIO_LOW);
/*set the display on*/
lcdWriteByte(LCD_DISPLAY_ON_COMMAND);
digitalPinWrite(LCD_RS, GPIO_HIGH);
genLCDUpdateState = LCD_UPDATE_POS; /*default state*/
break;

Struggling with the output of ADC on a PIC18F252

I've recently finished code for a PIC18F252 which uses the built in ADC to convert analogue inputs from 3 sensors into digital outputs that can be sent to motors. The code builds and uploads to the PIC perfectly fine, but unfortunately just doesn't work, and I'm struggling to see where the issue is.
After testing the output ports for the motors, I've found that they are all outputting the same signal, when they shouldn't be, and it doesn't change depending on the sensors.
My first thought is that there's something wrong between the output of the ADC (loading the result from ADRESH), and the if statements used to assign a digital value to these outputs.
I can't upload the entire code as this is coursework, but I've added the relevant parts. I've only included my function for AD conversion using one channel, but the functions for the other two channels are the same, just changing variables.
If anyone is able to spot an issue with this code (presumably around the if statements) I would be grateful!
#include <p18F252.h> // PIC specific definitions
#include <xc.h> // Xc8 compiler specifics
#include <stdio.h> // Standard C I/O library
#include <stdlib.h> // Standard C library
// Function declarations
void Config_ADC(void);
void delay(void);
void Motor_Output(unsigned char x, unsigned char y, unsigned char z);
void channel3(void);
unsigned char leftSens = 0b00000000; //Initialise left sensor variable
void Config_ADC(void){
// ADC Setup
TRISA = 0xFF; // configure port A as inputs
ADCON1bits.ADFM =0; // left justified
ADCON1bits.PCFG3=0;
ADCON1bits.PCFG2=1;
ADCON1bits.PCFG1=0;
ADCON1bits.PCFG0=0;
ADCON1bits.ADCS2=0;
ADCON0bits.ADCS1=1;
ADCON0bits.ADCS0=0;
ADCON0bits.ADON =1;
}
// Function for a delay of 1ms
void delay(void){
T2CON = 0x49; // start counting from 73
PR2 = 0x7C; // stop count at 124
T2CONbits.TMR2ON = 1; // activate timer 2
while(!PIR1bits.TMR2IF); // wait for timer flag
T2CONbits.TMR2ON = 0; // stop timer 2
PIR1bits.TMR2IF = 0; // clear flag
}
void channel3(void){
ADCON0bits.CHS2 = 0; //Channel selection
ADCON0bits.CHS1 = 1;
ADCON0bits.CHS0 = 1;
delay(); // Acquisition time to charge hold capacitor
ADCON0bits.GO_DONE = 1; // Start Conversion
while(ADCON0bits.GO_DONE); // Wait for A/D Conversion to complete
leftSens = ADRESH; // Return result
}
void main(void){
TRISB = 0x00; // configure Port B as output
Config_ADC(); // load ADC
while(1) { //loop forever/
channel3(); // Call channel 3 conversion
Motor_Output(leftSens, middleSens, rightSens);
}
}
// Function to send instructions to motors
void Motor_Output(unsigned char x, unsigned char y, unsigned char z){
int left, middle, right;
if(x >= 173){left = 1;} //173 chosen as threshold 8 bit value
else if(x < 173){left = 0;}
else if(y >= 173){middle = 1;}
else if(y < 173){middle = 0;}
else if(z >= 173){right = 1;}
else if(z < 173){right = 0;}
unsigned char output;
output = (left << 2) | (middle << 1) | right; //Bit shifted variables into one value
switch(output){
case 0x0:
PORTBbits.RB7 = 0; //Test for each output and activate motors accordingly
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x1:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 1;
PORTBbits.RB4 = 0;
case 0x2:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x3:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 1;
PORTBbits.RB4 = 0;
case 0x4:
PORTBbits.RB7 = 1;
PORTBbits.RB6 = 0;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x5:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x6:
PORTBbits.RB7 = 1;
PORTBbits.RB6 = 0;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
case 0x7:
PORTBbits.RB7 = 0;
PORTBbits.RB6 = 1;
PORTBbits.RB5 = 0;
PORTBbits.RB4 = 1;
}
return;
}
Without going any deeper in analysis there are two major problems:
The if-else if-chain will do just one assigment to left. To make that obvious I have indented your source this way without any other changes:
if (x >= 173) { // Either THIS...
left = 1;
} else
if (x < 173) { // Or THAT will be true.
left = 0;
} else // None of the following is executed therefore.
if (y >= 173) {
middle = 1;
} else
if (y < 173) {
middle = 0;
} else
if (z >= 173) {
right = 1;
} else
if (z < 173) {
right = 0;
}
So middle and right will have undefined values.
All your cases in the switch are missing a break. So only the last case or none at all will be executed. Why "none"? Because middle and right have undefined values, resulting in a random value in output.
Note: "Random" might be always the same value, depending on the bits set or reset at the locations of middle and right, respectively.
Quick question: Is it by design that you are falling through your switch-cases?
void Motor_Output(unsigned char x, unsigned char y, unsigned char z){
// ...
switch(output){
case 0x0:
... <-- no break, will continue to execute next case
case 0x1:
... <-- no break, will continue to execute next case
case 0x2:
... <-- no break, will continue to execute next case
case 0x3:
... <-- no break, will continue to execute next case
case 0x4:
... <-- no break, will continue to execute next case
case 0x5:
... <-- no break, will continue to execute next case
case 0x6:
... <-- no break, will continue to execute next case
case 0x7:
... <-- no break, will continue to execute next case
}
return;
}

C language switch-case: avoiding a case after used once

I'm trying a challenge where I need to get a random number, and print the sum of the digits inside the number without duplicates:
for example, 123 will print 6 ( 1 + 2 + 3 ), and 32111 will do the same ( because we don't add duplicates to our sum, the sum of this number is similar to the sum of 123. )
In my solution I thought about using switch case for each number, and use a flag that its value is one, than in each case I add 1 to the flag, and when the flag is 2 I add the number to the sum, but I don't know how to avoid a case after it happend, which if I see it correctly will avoid me using multiple flags for each number (because if we could avoid a case after it happend, i just could set the flag back to one after the switch and do all the process again )
can you help me out? thanks a lot!
#include <stdio.h>
#define TEN 10
#define NINE 9
#define EIGHT 8
#define SEVEN 7
#define SIX 6
#define FIVE 5
#define FOUR 4
#define THREE 3
#define TWO 2
#define ONE 1
int main(void)
{
int answer = 0, i = 0, remain = 0, sum = 0, flag = 1;
printf("Enter a number: ");
scanf("%d", &answer);
while(answer >= ONE)
{
remain = answer % TEN;
answer /= TEN;
printf("%d\n", remain);
switch (remain)
{
case ONE:
{
flag++;
if (flag == TWO)
{
sum = sum + ONE;
}
break;
}
case TWO:
{
flag++;
if (flag == TWO)
{
sum = sum + TWO;
}
break;
}
case THREE:
{
flag++;
if (flag == TWO)
{
sum = sum + THREE;
}
break;
}
case FOUR:
{
flag++;
if (flag == TWO)
{
sum = sum + FOUR;
}
break;
}
case FIVE:
{
flag++;
if (flag == TWO)
{
sum = sum + FIVE;
}
break;
}
case SIX:
{
flag++;
if (flag == TWO)
{
sum = sum + SIX;
}
break;
}
case SEVEN:
{
flag++;
if (flag == TWO)
{
sum = sum + SEVEN;
}
break;
}
case EIGHT:
{
flag++;
if (flag == TWO)
{
sum = sum + EIGHT;
}
break;
}
case NINE:
{
flag++;
if (flag == TWO)
{
sum = sum + NINE;
}
break;
}
default:
{
}
}
}
printf("The sum of the number is: %d", sum);
return 0;
}
Try using a bitmask representing each case. The main idea is to keep track for each number (from 0 to 9) using only one integer. Some bit of this single integer can be used as to find whether this number was seen before or not. If the bit is 0 then the corresponding number is seen for the first time (and we now set the bit to 1), and if we see that the bit is already 1, then we don't add it into our final sum.
int mask = 0;
switch (remain) {
case 1: // 001
if ((mask & 1) == 0) { // 1 = 1 << 0
sum += 1;
mask |= 1;
}
break;
...
case 3: // 100
if ((mask & 4) == 0) { // 4 = 1 << 2
sum += 3;
mask |= 4;
}
break;
...
case n:
if ((mask & k) == 0) { // k = 1 << (n-1)
sum += n;
mask |= k;
}
break;
...
Now you can see a pattern in the last case I used, we can simplify this switch-case into a single if statement.
int mask = 0;
int sum = 0;
while (answer) {
remain = answer % 10;
answer /= 10;
int offset = remain;
int flag = 1 << offset;
if ((mask & flag) == 0) {
sum += remain;
mask |= flag;
}
}
// sum contains the required answer
Each bit represents one of the cases, since you have only 10 cases this is the most efficient way to track the flags as you have more than 10 bits for an integer and it will be wastage to have a separate boolean flag for 0 to 9.
A case-term is a compile time constant, so you cannot "disable" it at runtime at the c language level. You would have to introduce a separate flag for each digit then.
I'd say - and have a look at you code - the switch-case approach is not the best as you duplicate a lot of similar code. A much easier way would be to have an array of 10 ints, each standing for a particular digit, and once a digit is encountered, set the respective array element to 1. At the end sum up in a loop.
If you have troubles getting this approach running, don't hesitate to ask again...

Atmel microprocessor and rotary encoder controlling speed of 7 segment display

I am trying to get a rotary encoder to control the speed of a 7 segment display counting from 0-9 with the Atmel (ATmega328P Xplained mini) microprocessor. My problem is that whenever I run the program the display just counts faster and faster until you can just see an "8", sometimes it seems that I can keep the speed down by turning the rotary encoder CCW and sometimes no effect at all. As I am not that experienced in programming and especially not this stuff I hope someone is capable and willing to help.
Here is my code:
#include <avr/io.h>
void Display (uint8_t x)
{
static uint8_t tabel[] =
{0b11000000,0b11111001,0b10100100,0b10110000,0b10011001,0b10010010,0b10000010,0b11111000,0b10000000,0b10010000};
PORTD = tabel[x];
}
int GetInput (void)
{
uint8_t x = PINC&1;
uint8_t y = (PINC>>1)&1;
if (x == 0 && y == 0) {return 0; }
else if (x == 1 && y == 0) {return 1;}
else if (x == 0 && y == 1) {return 2;}
else {return 3;}
}
int main(void)
{
DDRD = 0xFF; // set PortD as an output
DDRC = 0x00; // set PortC as an input
PORTB = 0x03; // Activate Pull-up resistors
float d = 9000;
int tick = 0;
int i = 0;
int input, state = 0; // initial state
int oldInput = 0;
while (1)
{
input = GetInput();
if (oldInput == 0 && input == 1)
{
d = (d * 1.1);
//slower
}else if (oldInput == 0 && input == 2)
{
d = (d * 0.9);
//faster
}else if (oldInput == 1 && input == 0)
{
d = (d * 0.9);
//faster
}else if (oldInput == 1 && input == 3)
{
d = (d * 1.1);
//slower
}else if (oldInput == 2 && input == 0)
{
d = (d * 1.1);
//slower
}else if (oldInput == 2 && input == 3)
{
d = (d * 0.9);
//faster
}else if (oldInput == 3 && input == 1)
{
d = (d * 0.9);
//faster
}else if (oldInput == 3 && input == 2)
{
d = (d * 1.1);
//slower
}
oldInput = input;
switch (state)
{
case 0: //ini
Display(0);
state = 1;
break;
case 1: //count
if (i == 9)
{
i = 0;
Display(i);
}
else
{
i++;
Display(i);
}
state = 2;
break;
case 2: // delay
if (tick < d)
{
state = 2;
tick++;
}
else
{
state = 1;
tick = 0;
}
break;
case 3: //reset / destroy
break;
}
}
}
First try changing the GetInput function to return a more useful value. Note that bit 0 and bit 1 of PINC already combine to form the integer that you're reconstructing.
int GetInput (void)
{
// array to convert grey scale bit patterns to direction indicators.
// Rows indexed by lastValue, columns indexed by thisValue, and the
// content is -1 for CCW, +1 for CW, 0 for no motion. Note that 0 is
// also used for an invalid transition (2 bits changed at once), but a
// different value could be used for fault detection.
static const int tableGreyToDirection[4][4] =
{
0 , -1, 1 , 0 , // lastValue==0
1 , 0 , 0 , -1, // lastValue==1
-1, 0 , 0 , 1 , // lastValue==2
0 , 1 , -1, 0 // lastValue==3
};
static uint8_t lastValue = 0; // A valid default starting value
uint8_t thisValue = (PINC & 0b00000011); // Use the bottom two bits as a value from 0..3
int result = tableGreyToDirection[lastValue][thisValue];
lastValue = thisValue;
return result;
}
You can then simplify the test in the loop greatly.
while (1)
{
// Check the direction of the encoder: -1 = CCW, +1 = CW, anything else = no motion.
input = GetInput();
if(0 < input)
{
// Motion is CW, so increment the delay (within reasonable bounds).
if(8900 > d) d += 100;
}
else if(0 > input)
{
// Motion is CCW, so decrement the delay (within reasonable bounds).
if(100 < d) d -= 100;
}
// Keep the rest as it is...
}
It would be advisable to change d to be a uint16_t and tidy it up a little. Further tips include using #define to provide readable names for constants. E.g. in my table of directions you could use:
#define ENCODER_CW 1
#define ENCODER_CCW -1
#define ENCODER_NEITHER 0
...
static const int tableGreyToDirection[4][4] =
{
ENCODER_NEITHER, ENCODER_CCW, ENCODER_CW, ENCODER_NEITHER, // lastValue==0
...
I'm sure you can fill it out yourself.
I checked your SW, but I can't find big issue instantly.
You'd better check below part.
If you didn't touch the encoder but speed is faster and faster
: do you have a scope to check the encoder input port whether noise is input from the port or not.
If two input port is stable, please check your value also stable
: old input and new input value should be same
: check by log or output toggle unused port when the value is changed. you can debug your own code.
You'd better add amount tick value than multiply directly to prevent d value becomes 0.
your CPU has to run as fast as detect port status change in main loop. - I think it is possible if this code is all of your system.

C programming exercise?

I'm reading a book on C programming and try to do the exercises:
Write a program that prints a horizontal histogram consisting of stars(*). One star for every number there can be in the interval 0 ... 70.
#include <stdio.h>
void draw_stars(int number_of_stars) {
int counter = 0;
for(counter = 0; counter < number_of_stars; counter++) {
printf("*");
}
printf("\n");
}
int main(void) {
int counter1, counter2, ones, tens, zero, one, two, three, four, five, six, seven, eight, nine = 0;
for(tens = 0; tens < 7; tens++) {
if(tens == 0)
zero = zero + 1;
if(tens == 1)
one = one + 10;
if(tens == 2)
two = two + 10;
if(tens == 3)
three = three + 10;
if(tens == 4)
four = four + 10;
if(tens == 5)
five = five + 10;
if(tens == 6)
six = six + 10;
if(tens == 7)
seven = seven + 10;
for(ones = 0; ones < 9; ones++) {
if(ones == 0)
zero++;
if(ones == 1)
one++;
if(ones == 2)
two++;
if(ones == 3)
three++;
if(ones == 4)
four++;
if(ones == 5)
five++;
if(ones == 6)
six++;
if(ones == 7)
seven++;
if(ones == 8)
eight++;
if(ones == 9)
nine++;
}
}
draw_stars(zero);
draw_stars(one);
draw_stars(two);
draw_stars(three);
draw_stars(four);
draw_stars(five);
draw_stars(six);
draw_stars(seven);
draw_stars(eight);
draw_stars(nine);
}
For some reason my program enters a infinite loop printing stars. But I can't find out why?
I haven't been able to come up with any other solution, but I still think it's ugly and bloated. How would a real C programmer solve this?
Edit:
After reading and understanding the chapter about arrays in the book, I was able to write a more clean version of the program. I'm posting it here as it might help other beginners understand the use of arrays. Writing an identical program in terms of output, but using different functionality of the language is a great learning experience.
#include <stdio.h>
#define TENS 7
void draw_stars(int stars) {
int star_counter = 0;
for (star_counter = 0; star_counter < stars; star_counter++)
printf("%c", '*');
}
int main(void) {
int number_array[10];
int tens_counter, ones_counter;
for (ones_counter = 0; ones_counter < 10; ones_counter++)
number_array[ones_counter] = 0;
for (tens_counter = 0; tens_counter < TENS; tens_counter++) {
if (tens_counter != 0)
number_array[tens_counter] += 10;
else
number_array[tens_counter] += 1;
for (ones_counter = 0; ones_counter < 10; ones_counter++)
number_array[ones_counter]++;
}
for (ones_counter = 0; ones_counter < 10; ones_counter++) {
draw_stars(number_array[ones_counter]);
printf("\n");
}
}
Initialize all variables:
int counter1=0, counter2=0, ones=0, tens=0, zero=0, one=0..
BTW, for better performance,
replace if with else if except the first one in the block. Why do you want to check all if conditions when you already know only one is true?
FYI, when a condition is true in Else if, all other ifs are skipped.
If you wanted to initialize all ints to zero, you should write:
int counter1=0, counter2=0, ...
Now only nine is init by 0, other variables contain rubbish - arbitrary values.
in main() you have to initialize all variable with zero like
int counter1=0,counter2=0 and so on
otherwise it take garbage value and perform operation with those values and then output will be like
********
*****************
*****************
*****************
*****************
*****************
*****************
*******
*******

Resources