optimization code - 2D-array indexing in c - 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;

Related

C, help continue..? in while loop - polynomial ADT

When the coef is 0, I used continue to not print, but only printTerm(a) comes out and the printTerm(b) part does not come out.
When I delete the (if & continue) statement, both printTerm(a) and printTerm(b) appear, so it seems that there is a problem here (if & continue) statement.
How can I solve this?
int main() {
a[0].coef = 2;
a[0].expon = 1000; // 2x^1000
a[1].coef = 1;
a[1].expon = 2; // x^2
a[2].coef = 1;
a[2].expon = 0; // 1
b[0].coef = 1;
b[0].expon = 4; // x^4
b[1].coef = 10;
b[1].expon = 3; // 10x^3
b[2].coef = 3;
b[2].expon = 2; // 3x^2
b[2].coef = 1;
b[2].expon = 0; // 1
printTerm(a);
printTerm(b);
return 0;
}
void printTerm(polynomial *p) {
int i=0;
printf("polynomial : ");
while(p[i].expon != -1) {
if(p[i].coef == 0) continue;
printf("%dx^%d", p[i].coef, p[i].expon);
i++;
if(p[i].expon != -1 && p[i].coef > 0) printf(" + ");
}
printf("\n");
}
Because you only increment i if p[i].coef is not equal to 0.
If p[i].coef == 0 it skips the increment part and function is stuck in infinite loop, always checking the same array item.
EDIT:
Way to fix this:
Instead of if(p[i].coef == 0) continue; use:
if (p[i].coef == 0)
{
i++;
continue;
}
This way while loop evaluetes next array item instead of being stuck on the same.

Go to a line number in embedded C outside of the function

Is it possible to call a line number in embedded C that is outside of the function?
Simple goto label commands can't work because I am in the if statement loop: I want to restart the function once the error is greater than 200.
void followWall(void)
{
begin:
int desired = getADC(); //store the first ADC reading as the desired distance from the wall
int right = 200; //pre set all variables to be called in the drive function
int left = 200; //ints are needed here for bit masking later on to stop overflow
char rightH = 0;
char leftH = 0;
float k = 0.5; //constant to times the error to fine tune the response
drive(rightH,right,leftH,left); //drive the robot to the pre set variables
while( bumpFlag == 0 ) //while the robot has not been bumped or encounted a cliff
{
int actual = getADC(); //call a new ADC reading everytime at start of while as the current reading
rightH = 0;
leftH = 0; //set variables back to default to stop constant increase and decrease in variables
left = 200;
right = 200;
char error = abs(actual-desired); //calculate the error by minusing the actual distance to the desired
if(motorAngle < 180) //wall on left between 1st and 2nd quadrant
{
if(error > 200)
{
stop();
moveStepper(33,0);
goto begin;
}
if (actual > desired)
{
right -=((error)*k);
left += ((error)*k);
}
else if (actual < desired)
{
left -=((error)*k);
right +=((error)*k);
}
}
else if (motorAngle > 180)
{
if(error > 200)
{
stop();
moveStepper(33,1);
goto begin;
}
if (actual > desired)
{
left -=((error)*k);
right +=((error)*k);
}
else if (actual < desired)
{
right -=((error)*k);
left +=((error)*k);
}
}
drive(rightH,right,leftH,left); bumpSensor();
setLCDCursor(0x09);
writeLCDNumber(convert(actual)); //constantly write the converted AC value on the LCD
}
stop(); //stop the robot
}
You should restructure your code to avoid a GOTO. Another loop is needed. Something like this.
void followWall(void)
{
repeat = 0;
do // add this loop here
{
...
...
while( bumpFlag == 0 )
{
repeat = 0;
..
..
if(motorAngle < 180)
{
..
if(error > 200)
{
..
..
repeat = 1;
break;
}
}
else if (motorAngle > 180)
{
..
if(error > 200)
{
..
..
repeat = 1;
break;
}
}
}
} while (repeat == 1);
}

Checking for valid moves in Reversi for all 8 directions

I have a function to check the valid moves in my reversi game. I look at the unoccupied spaces, and check if an adjacent space in any 8 directions are the opposite piece. (If I'm black, I search for white) Now, if I find a piece that's adjacent, I should keep looking towards that direction and see if my own piece is at the end, then I return true, else if its an unoccupied space or off the board boundaries, I return false.
My function doesn't seem to work properly as I print out the wrong moves.
bool checkLegalInDirection(char boardgame[26][26], int size, int row, int col, char color) {
int currentRow, currentCol;
for (int deltaRow = -1; deltaRow < 2; deltaRow++) {
for (int deltaCol = -1; deltaCol < 2; deltaCol++) {
if (deltaRow == 0 && deltaCol == 0) {
break;
} else {
row = row + deltaRow;
col = col + deltaCol;
if (positionInBounds(size, row, col)) {
while (boardgame[row][col] == OppositeColor(color)) {
currentRow = row + deltaRow;
currentCol = col + deltaCol;
if (positionInBounds(size, currentRow, currentCol)) {
if (boardgame[currentRow][currentCol] == color) {
return true;
} else {
return false;
}
}
}
}
}
}
}
}
deltaRow and deltaCol are the increments that go in each direction and add one time to keep searching in a specified location. PositioninBounds is a function I have to make sure my searches are within the board boundaries. My deltarow and deltacol cannot be both 0 at the same time, so somehow I need to skip that step, (which I probably did wrong). Oppositecolor is a function that returns me the opposite color of my own piece.
I think your code has multiple mistakes.
Your code is incorrectly breaking the for loop when you should be continuing with the next iteration (as mentioned by chux).
Change...
if (deltaRow == 0 && deltaCol == 0) {
break;
} else {
...
}
to either chux's suggestion...
if (deltaRow == 0 && deltaCol == 0) {
continue;
} else {
...
}
or to an even simpler solution...
if (deltaRow != 0 || deltaCol != 0) {
...
}
Inside the deltaRow/deltaCol loops, your code is incorrectly modifying the original row/col values which your code will need in later loop iterations.
You can change...
row = row + deltaRow;
col = col + deltaRow;
to...
currentRow = row + deltaRow;
currentCol = col + deltaRow;
Inside the while loop, your code is incorrectly returning false. You can not return false until you have completed all the for loops.
Before entering the while loop, you need to check that the adjacent space is in bounds and opposite color...
if (positionInBounds(size, currentRow, currentCol) && boardgame[currentRow][currentCol] == OppositeColor(color)) {
If so, then skip over all adjacent opposite colors...
while (positionInBounds(size, currentROw, currentColor) && boadgame[currentRow][currentCol] == OppositeColor(color)) {
{
currentRow = currentRow + deltaRow;
currentCol = currentCol + deltaCol;
}
After you have skipped over opposite colors then you need to check for same color. If so then return true.
if (positionInBOunds(size, currentRow, currentCol) && boardgame[currentRow][currentCol] == color) {
return true;
}
You code should only return false after checking all directions...
for (int deltaRow = -1; deltaRow < 2; deltaRow++) {
for (int deltaCol = -1; deltaCol < 2; deltaCol++) {
....
}
}
return false;

Interfacing a 4x4 keypad matrix with Atmega32

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

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.

Resources