Rotationsenkoder, C
Hej! Jag försöker lösa denna gamla tentauppgiften:
Tänker jag rätt? Jag gör ju ingenting med informationen om 256 steg, vad borde jag ändra för att lösa denna uppgift?
#include <stdio.h>
typedef enum {
State_00 = 0b00,
State_01 = 0b01,
State_10 = 0b10,
State_11 = 0b11
} EncoderState;
typedef enum {
Rotation_None = 0,
Rotation_CW = 1,
Rotation_CCW = -1
} RotationEvent;
//Global Variables
volatile EncoderState prevState = State_00;
volatile EncoderState currState = State_00;
volatile int menu = 0;
volatile int flag = 0;
//Prototypes
//Functions
int8_t decodeRotation(EncoderState prevState, EncoderState currState)
{
switch (prevState)
{
case (State_00):
{
if (currState == State_10)
{
menu++;
return Rotation_CW;
}
else if (currState == State_01)
{
menu--;
return Rotation_CCW;
}
break;
}
case (State_10):
{
if (currState == State_11)
{
menu++;
return Rotation_CW;
}
else if (currState == State_00)
{
menu--;
return Rotation_CCW;
}
break;
}
case (State_11):
{
if (currState == State_01)
{
menu++;
return Rotation_CW;
}
else if (currState == State_10)
{
menu--;
return Rotation_CCW;
}
break;
}
case (State_01):
{
if (currState == State_00)
{
menu++;
return Rotation_CW;
}
else if (currState == State_11)
{
menu--;
return Rotation_CCW;
}
}
default:
return Rotation_None;
}
}
//Callback
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
ChannelA = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_0);
ChannelB = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_1);
currState = (EncoderState)(channelA << 1 | channelB);
flag++;
}
//Main
int main(void)
{
//Inits
HAL_TIM_Base_Start_IT(&htim1);
TextLCD_Init(&lcd, &hi2c1, 0x4E);
char str[10] = {'\0'};
while(1)
{
if (flag)
{
TextLCD_Clear(hlcd);
sprintf(str, "Menu:%.2f", menu);
}
flag--;
}
}
Som jag uppfattar det bör du ta hänsyn till 256 genom att begränsa menu. Om jag börjar på 0 och vrider ett helt varv ska jag ju hamna på 0 igen, inte på 256.
Nej vänta, det står ju ingenstans att displayen bara kan visa 0-255.
Kom precis på en grej. Nu uppdateras meny värdet varje gång jag byter state istället för varje gång enkodern har snurrat ett varv. Detta är väl fel? En full rotation ska väl göra att meny värdet ökar eller minskar med 1 beroende på riktning? Detta har nog inget med detent att göra dock.
Oklart från uppgiften om ett helt varv eller bara ett "snäpp" krävs för att något ska hända.
Dock eftersom det är ett menysystem så kan jag tänka mig att det finns väldigt få alternativ och att det inte ska krävas pyttesmå vridningar för att landa på det man tänkt sig, så ja, du ska nog kolla efter hela varv =)
Jag har gjort några förändringar, så här går mina tankar nu:
#include <stdio.h>
typedef enum {
IDLE_11, //0
ChannelA_01, //1
ChannelA_00, //2
ChannelA_10, //3
ChannelB_10, //4
ChannelB_00, //5
ChannelB_01 //6
} EncoderState;
int state = IDLE_11;
int menu = 0;
int currState = 0;
int prevState = 0;
int flag = 0;
//StateMachine
void stateMachine()
{
if (prevState != currState)
{
switch (state)
{
case IDLE_11:
if (currState == 0x01)
{
state = ChannelA_01;
}
else if (currState == 0x10)
{
state = ChannelA_10;
}
break;
case ChannelA_01:
if (currState == 0x00)
{
state = ChannelA_00;
}
else if (currState == 0x11)
{
state = IDLE_11;
}
break;
case ChannelA_00:
if (currState == 0x10)
{
state = ChannelA_10;
}
else if (currState == 0x01)
{
state = ChannelA_01;
}
break;
case ChannelA_10:
if (currState == 0x11)
{
menu++; //ONE FULL ROTATION CW
state = IDLE_11;
}
break;
case ChannelB_10:
if (currState == 0x00)
{
state = ChannelB_00;
}
else if (currState == 0x11)
{
state = IDLE_11;
}
break;
case ChannelB_00:
if (currState == 0x01)
{
state = ChannelB_01;
}
else if (currState == 0x10)
{
state = ChannelB_10;
}
break;
case ChannelB_01:
if (currState == 0x11)
{
menu--; //ONE FULL ROTATION CCW
state = IDLE_11;
}
break;
default:
state = IDLE_11;
break;
}
prevState = currState;
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
int ChannelA = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_0);
int ChannelB = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_1);
currState = (ChannelA << 1 | ChannelB);
flag++;
}
int main(void)
{
//Inits
HAL_TIM_Base_Start_IT(&htim1);
TextLCD_Init(&lcd, &hi2c1, 0x4E);
char str[10] = {'\0'};
while(1)
{
if (flag)
{
stateMachine();
TextLCD_Clear(hlcd);
sprintf(str, "Menu:%d", menu);
TextLCD_PutStr(hlcd, str);
flag--;
}
}
}
Vad tror ni?
Jag ser inte att du tar hänsyn till att det krävs många hopp för ett helt varv. Det står i uppgiften att den har 256 steg, men du verkar räkna typ det fjärde hoppet som ett varv.
Jag tycker prylen verkar svåranvänd. Om man ska välja alternativ 7 i menyn och man står på 1 så ska man alltså vrida antingen sex småsnäpp medurs, eller sex hela varv. Jag skulle nog vilja att typ en 30 graders vridning gjorde att något hände (gå från 1 till 2 t.ex.), alltså ungefär 20 småsnäpp, men det gör koden mer komplicerad än det troligen är meningen.
Så det är nog småsnäpp man ska programmera för, tycker jag.
Om man råkar vrida ett helt varv så är det nog bra om det blir 0 och inte 256 eller -256, så man slipper vrida hela vägen tillbaka, men man borde kunna räkna med att man håller sig mellan 0 och något litet tal, t.ex. 10.
Har någon sett en sådan här ratt som ger input till ett menysystem i verkligheten?
Laguna skrev:Jag tycker prylen verkar svåranvänd. Om man ska välja alternativ 7 i menyn och man står på 1 så ska man alltså vrida antingen sex småsnäpp medurs, eller sex hela varv. Jag skulle nog vilja att typ en 30 graders vridning gjorde att något hände (gå från 1 till 2 t.ex.), alltså ungefär 20 småsnäpp, men det gör koden mer komplicerad än det troligen är meningen.
Så det är nog småsnäpp man ska programmera för, tycker jag.
Om man råkar vrida ett helt varv så är det nog bra om det blir 0 och inte 256 eller -256, så man slipper vrida hela vägen tillbaka, men man borde kunna räkna med att man håller sig mellan 0 och något litet tal, t.ex. 10.
Har någon sett en sådan här ratt som ger input till ett menysystem i verkligheten?
Det har du helt rätt i. Det ska onekligen vara småsnäpp man ska programmera för.
Dessa två alternativ på lösning är dock de enda jag kan komma på, så om någon kan hjälpa mig lite så vore det uppskattat!
En teknisk detalj: hur får man texten till displayen? Du skriver den till strängen str, men det är allt.
Laguna skrev:En teknisk detalj: hur får man texten till displayen? Du skriver den till strängen str, men det är allt.
Oj, hade visst missat att lägga till TextLCD_PutStr. Den bygger på en labb vi gjort tidigare i kursen, men det hör inte till uppgiften. Vi ska nog bara simulera hur själva main.c filen borde se ut.
Jag kommer nog inte komma på nåt bättre sätt än så här för att lösa uppgiften. Tar gärna emot feedback.
#include <stdio.h>
typedef enum {
IDLE_11, //0
ChannelA_01, //1
ChannelA_00, //2
ChannelA_10, //3
ChannelB_10, //4
ChannelB_00, //5
ChannelB_01 //6
} EncoderState;
int state = IDLE_11;
int menu = 0;
int currState = 0;
int prevState = 0;
int flag = 0;
//StateMachine
void stateMachine()
{
if (prevState != currState)
{
switch (state)
{
case IDLE_11:
if (currState == 0x01)
{
state = ChannelA_01;
menu++;
}
else if (currState == 0x10)
{
state = ChannelA_10;
menu--;
}
break;
case ChannelA_01:
if (currState == 0x00)
{
state = ChannelA_00;
menu++;
}
else if (currState == 0x11)
{
state = IDLE_11;
menu--;
}
break;
case ChannelA_00:
if (currState == 0x10)
{
state = ChannelA_10;
menu++;
}
else if (currState == 0x01)
{
state = ChannelA_01;
menu--;
}
break;
case ChannelA_10:
if (currState == 0x11)
{
menu++;
state = IDLE_11;
}
break;
case ChannelB_10:
if (currState == 0x00)
{
state = ChannelB_00;
menu--;
}
else if (currState == 0x11)
{
state = IDLE_11;
menu++;
}
break;
case ChannelB_00:
if (currState == 0x01)
{
state = ChannelB_01;
menu--;
}
else if (currState == 0x10)
{
state = ChannelB_10;
menu++;
}
break;
case ChannelB_01:
if (currState == 0x11)
{
menu--;
state = IDLE_11;
}
break;
default:
state = IDLE_11;
break;
}
prevState = currState;
}
}
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
int ChannelA = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_0);
int ChannelB = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_1);
currState = (ChannelA << 1 | ChannelB);
flag++;
}
int main(void)
{
//Inits
HAL_TIM_Base_Start_IT(&htim1);
TextLCD_Init(&lcd, &hi2c1, 0x4E);
char str[10] = {'\0'};
while(1)
{
if (flag)
{
stateMachine();
TextLCD_Clear(hlcd);
sprintf(str, "Menu:%d", menu);
TextLCD_PutStr(hlcd, str);
flag--;
}
}
}