I am programming C on an Arduino and I am very much a beginner. My goal with this program is to display a binary number on LED's and then let the player guess the binary number. The player then presses a button equal to the decimal value of the displayer binary number. When the players starts pressing the button, they get two seconds for every press. If they don't click again in those two seconds they lose, or they guess the right amount and win.
The only thing my messy program doesn't do is give a two second period every button press. Even after extensive reading I am confused on milli();. Aside from the bad coding, could I change something in my program to give players a two second window when pressing the button? I am convinced that there is a just a minute detail that I am overlooking. Thanks for your time.
const int buttonPin = 2;
const int ledPinValue1 = 3;
const int ledPinValue2 = 4;
const int ledPinValue4 = 5;
const int ledPinValue8 = 6;
int teller = 0;
int buttonStatus = 0;
int lastButtonStatus;
unsigned long interval=5000; // the time we need to wait
unsigned long previousMillis = 0; // millis() returns an unsigned long.
unsigned long currentMillis = 0;
unsigned long elapsed;
unsigned long midElapsed;
unsigned long minus=5000;
int secondLoop = 0;
boolean allowTimer = false;
boolean allowMilliAfterFirstRound; //without this, when the second loop commences milli = milli - milli
void setup() {
Serial.begin(9600);
pinMode(ledPinValue1, OUTPUT);
pinMode(ledPinValue2, OUTPUT);
pinMode(ledPinValue4, OUTPUT);
pinMode(ledPinValue8, OUTPUT);
pinMode(buttonPin, INPUT);
}
void loop() {
boolean initiateLoss = true; // ++++
int randomNumber = 5; //Replace with randomcode
currentMillis = millis();
knopStatus = digitalRead(buttonPin);
if (randomNumber == 1 || randomNumber == 3 || randomNumber == 5 || randomNumber == 7 || randomNumber == 9 || randomNumber == 11 || randomNumber == 13 || randomNumber == 15){
digitalWrite(ledPinValue1, HIGH);
}
else {
digitalWrite(ledPinValue1, LOW);
}
if (randomNumber == 2 || randomNumber == 3 || randomNumber == 6 || randomNumber == 7 || randomNumber == 10 || randomNumber == 11 || randomNumber == 14 || randomNumber == 15){
digitalWrite(ledPinValue2, HIGH);
}
else {
digitalWrite(ledPinValue2, LOW);
}
if (randomNumber == 4 || randomNumber == 5 || randomNumber == 6 || randomNumber == 7 || randomNumber == 12 || randomNumber == 13 || randomNumber == 14 || randomNumber == 15){
digitalWrite(ledPinValue4, HIGH);
}
else {
digitalWrite(ledPinValue4, LOW);
}
if (randomNumber == 8 || randomNumber == 9 || randomNumber == 10 || randomNumber == 11 || randomNumber == 12 || randomNumber == 13 || randomNumber == 14 || randomNumber == 15){
digitalWrite(ledPinValue8, HIGH);
}
else {
digitalWrite(ledPinValue8, LOW);
}
//------------------------------------------------------------------------------------
if (knopStatus != lastButtonStatus) {
if (knopStatus == HIGH) {
teller++;
Serial.print("number of button pushes: ");
Serial.println(teller, DEC);
allowTimer = true;
}
delay(50);
}
//------------------
if (allowTimer == true){
if (allowMilliAfterFirstRound == true) {
currentMillis = currentMillis - currentMillis;
allowMilliAfterFirstRound = false;
}
if (teller == randomNumber){ // WIN
Serial.print("You won!");
Serial.println();
initiateLoss = false;
randomNumber = 3; // remove when randomnumber is added
teller = 0;
previousMillis = millis();
}
if ((unsigned long)(currentMillis - previousMillis) > interval && initiateLoss == true) { // LOST!
elapsed = currentMillis - previousMillis;
Serial.print("Time elapsed at time of failure: ");
Serial.print(elapsed);
Serial.println();
Serial.print("currentMillis is now: ");
Serial.print(currentMillis); // 5000, 10000, 15000, 20000 etc
Serial.println();
Serial.print("previousMillis is now: ");
Serial.print(previousMillis); // 5000, 10000, 15000, 20000 etc
Serial.println();
previousMillis = millis();
Serial.println();
Serial.print("You lost!");
Serial.println();
Serial.print("Begin!");
Serial.println();
teller = 0;
}
}
lastButtonStatus = knopStatus; // save the current state as the last state, for next time through the loop
}
I would do something like this:
void loop() {
if (not yet displayed) {
[all the code to display the number on leds]
}
if (button pressed) {
allowTimer = true; // Start!
}
if (allowTimer) /* If timer started */ {
while (millis() - previousMillis <= 2000) /* The famous 2 sec */ {
if (button pressed) {
previousMillis = millis(); /* Update timing */
teller++;
}
}
if(teller == randomNumber) {
[Hooray, you won or whatever message and stuff you like]
}
else {
[Sorry, you lost]
}
}
Of course you should replace my writings with your code.
TIP: For a single instruction in any statement you don't need parentheses:
if (condition) {
onlyOneInstruction;
}
is the same as
if (condition) onlyOneInstruction;
EDIT: Also, you try to compare knopStatus (undeclared, maybe you meant buttonStatus) with lastButtonStatus, which isn't initialised. This gives you an error.
There's bugs, for instance:
if (allowMilliAfterFirstRound == true) {
currentMillis = currentMillis - currentMillis;
allowMilliAfterFirstRound = false;
}
And allowMilliAfterFirstRound is not initialized, nor assigned elswhere...
More generally, the code shows that you understand millis correctly. What's missing is a management of the 2 states the program can be in:
Display number, then waiting for the player's answer: counting time until timeout
Displaying a win/lost message, just waiting for a button press to start another guess (?)
previousMillis should be initialized when going from state 2 to 1.
Related
I'm trying to make a Whack-A-Mole game using an Arduino Mega with 10 LEDs (Moles) and 10 Push Buttons (Whack). The electronics are completed and tested, everything works fine. It also has a BLE radio attached which prompts the board to start one of three games I plan to do.
The problem I'm having is this:
In my main loop, I listen for a command from the app coming via BLE. When a "1" is sent by the app (serial pass through), I call the function
playGameOne();
The main thing is that everything loops in the main loop fine, but when I jump to the game function, it runs once and returns back to the main loop again. How can I keep the user looping in the game function until the game is over? Oh - and I'm not trying to use any Interrupts, but I imagine thats one way of doing it.
The latest incarnation of the game function looks like this:
//////////////////////////////////////////////
////////////////// GAME 1 //////////////////
void gameOne(){
//var int eTime;
// inform player game is about to begin
playCountdown();
Serial.println("Game Begun");
// initialize var to count time
elapsedMillis timeElapsed;
if(gameState < 1){
gameOneOne();
Serial.print("Game finished - Your time: ");
Serial.println(timeElapsed);
}
}
void gameOneOne(){
while(digitalRead(btPin31) == LOW){
// turn on LED45
digitalWrite(ledPin45, HIGH);
// wait for user to push corresponding button
if(digitalRead(btPin31) == HIGH){
// turn off the LED and jump to next LED - gameOneTwo()
digitalWrite(ledPin45, LOW);
gameOneTwo();
}
}
}
void gameOneTwo(){
while(digitalRead(btPin39) == LOW){
// turn on LED53
digitalWrite(ledPin53, HIGH);
if(digitalRead(btPin39) == HIGH){
digitalWrite(ledPin53, LOW);
// Finish the game, set state to 1
gameState = 1;
}
}
}
Not only this doesn't work, I highly doubt this is the proper way of coding games. In fact the ideal would be to have a Game Script that can be uploaded dynamically. The game Script would look like:
Header {name of game}
45 {pin of first LED}
500 {how long to keep it on, in ms}
49 {pin of the second LED}
500 {how long to keep it on, in ms}
... and so on
End of File
What is the best resource to learn this properly.
EDIT
Here's my main loop
// included header files
#include <elapsedMillis.h> // Measuring Elapsed Time Library
// Constant - Piezzo Speaker Pin
const int beepPin = 11; // the number of the Piezo Spkr pin
// Constants - Button Pins
const int btPin30 = 30;
const int btPin31 = 31;
const int btPin32 = 32;
const int btPin33 = 33;
const int btPin34 = 34;
const int btPin35 = 35;
const int btPin36 = 36;
const int btPin37 = 37;
const int btPin38 = 38;
const int btPin39 = 39;
// Constants - LED Pins
const int ledPin53 = 53;
const int ledPin52 = 52;
const int ledPin51 = 51;
const int ledPin50 = 50;
const int ledPin49 = 49;
const int ledPin48 = 48;
const int ledPin47 = 47;
const int ledPin46 = 46;
const int ledPin45 = 45;
const int ledPin44 = 44;
//Variable for storing BLUETOOTH received data
char data = 0;
// variables will change:
int buttonState = 0; // variable for reading the pushbutton status
int btPin30State = 0;
int btPin31State = 0;
int btPin32State = 0;
int btPin33State = 0;
int btPin34State = 0;
int btPin35State = 0;
int btPin36State = 0;
int btPin37State = 0;
int btPin38State = 0;
int btPin39State = 0;
// declare game state variable
int gameState = 0;
void setup() {
// initialize Serial Comms for Debug (0) and BT(3)
Serial.begin(9600); //Sets the buad for Serial (debug port)
Serial3.begin(9600); //Sets the baud for Serial3 data transmission
// initialize all button pins as INPUTs
for (int x = 30; x <= 39; x++){
pinMode(x, INPUT);
}
// initialize LED pins as OUTPUTs:
for (int i = 44; i <= 53; i++){
pinMode(i, OUTPUT);
}
// lightup all LEDs
for (int j = 44; j <= 53; j++){
digitalWrite(j, HIGH);
delay(100);
}
// prompt device is ready
Serial.println("Device Ready");
}
void loop() {
// Read Data from Serial3 -- This is to get initial game status/command from app/bluetooth
if(Serial3.available() > 0) { // Send data only when you receive data:
data = Serial3.read();
// See what the command is
if(data == '1') {
Serial.write("Send it to GameOne");
Serial.write("\n");
gameOne();
}
// See what the command is
if(data == '2') {
Serial.write("Send it to GameTwo");
Serial.write("\n");
gameTwo();
}
if(data == '3') {
Serial.write("Send it to GameThree");
Serial.write("\n");
gameThree();
}
if(data == '4') {
Serial.write("Test");
Serial.write("\n");
}
}
btPin30State = digitalRead(btPin30);
btPin31State = digitalRead(btPin31);
btPin32State = digitalRead(btPin32);
btPin33State = digitalRead(btPin33);
btPin34State = digitalRead(btPin34);
btPin35State = digitalRead(btPin35);
btPin36State = digitalRead(btPin36);
btPin37State = digitalRead(btPin37);
btPin38State = digitalRead(btPin38);
btPin39State = digitalRead(btPin39);
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if (btPin30State == HIGH) {
digitalWrite(ledPin44, HIGH);
tone(11, 1000, 500);
Serial.println("BTN 30 / LED 44");
gameOne();
} else {
digitalWrite(ledPin44, LOW);
}
if (btPin31State == HIGH) {
digitalWrite(ledPin45, HIGH);
Serial.println("BTN 31 / LED 45");
} else {
digitalWrite(ledPin45, LOW);
}
if (btPin32State == HIGH) {
digitalWrite(ledPin46, HIGH);
Serial.println("BTN 32 / LED 46");
} else {
digitalWrite(ledPin46, LOW);
}
if (btPin33State == HIGH) {
digitalWrite(ledPin47, HIGH);
Serial.println("BTN 33 / LED 47");
} else {
digitalWrite(ledPin47, LOW);
}
if (btPin34State == HIGH) {
digitalWrite(ledPin48, HIGH);
Serial.println("BTN 34 / LED 48");
} else {
digitalWrite(ledPin48, LOW);
}
if (btPin35State == HIGH) {
digitalWrite(ledPin49, HIGH);
Serial.println("BTN 35 / LED 49");
} else {
digitalWrite(ledPin49, LOW);
}
if (btPin36State == HIGH) {
digitalWrite(ledPin50, HIGH);
Serial.println("BTN 36 / LED 50");
} else {
digitalWrite(ledPin50, LOW);
}
if (btPin37State == HIGH) {
digitalWrite(ledPin51, HIGH);
Serial.println("BTN 37 / LED 51");
} else {
digitalWrite(ledPin51, LOW);
}
if (btPin38State == HIGH) {
digitalWrite(ledPin52, HIGH);
Serial.println("BTN 38 / LED 52");
} else {
digitalWrite(ledPin52, LOW);
}
if (btPin39State == HIGH) {
digitalWrite(ledPin53, HIGH);
Serial.println("BTN 39 / LED 53");
} else {
digitalWrite(ledPin53, LOW);
}
}
I think it would be ok to structure it something like this.
play_a_game:
for (some_number_of_times)
{
show_a_mole_and_let_them_wackit();
}
setup:
set up pins
say the game is starting
loop:
do
{
play_a_game();
}
while(game ending button not pressed and less then 10 moles have died);
say the game is over
i am currently working in a ardunio alarm clock project without and rtc for school. I have a problem with my hour variable not increasing and my conditionals that checks it.
This code mostly works i can set time in hr and minutes but when the timer reaches 59 minutes the hour doesnt increase by 1. The second code that has been posted is the bit where the problem lies. Any tips/help would be appreciated.
#include <Time.h>
#include <TimeLib.h>
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
#include <EEPROM.h>
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
const int numofMenus = 4;
int currentMenu = 0;
String menu[4][2] = {{"Set hour", "hr"}, {"Set minutes", "min"}, {"Set alarm", "o"}, {"Current Time", "ha"}};
int parameters[24];
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.noBlink();
}
void loop() {
inputAction();
if (currentMenu == 0)
{
printScreen();
}
if (currentMenu == 1)
{
printScreen();
}
if (currentMenu == 2)
{
printScreen();
}
if (currentMenu == 3)
{
int hr = parameters[0];
int mn = minute(parameters[1]);
int sec = second();
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
if (parameters[1] >= 0 && parameters[1] <= 59 && sec < 59) {
parameters[0];
printtime(parameters[0]);
}
else if (parameters[1] == 59 && second() == 59) {
if (parameters[0]>=0 && parameters[0]<24){
parameters[0];
printtime(parameters[0]++);
//delay(1000);}
/*else if (parameters[0] == 24){
parameters[0]= 0;
printtime(parameters[0]);
}*/
}
}
lcd.print(":");
if (sec >= 0 && sec < 59) {
printtime(parameters[1]);
}
else if (sec == 59) {
parameters[1];
printtime(parameters[1]++);
delay(1000);
}
lcd.print(":");
printtime(sec);
/* if (sec == 60) {
mn+1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
printtime(hr);
lcd.print(":");
printtime(mn);
lcd.print(":");
printtime(sec);
}
if (mn == 60) {
hr+1;
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Time: ");
printtime(hr);
lcd.print(":");
printtime(mn);
lcd.print(":");
printtime(sec);
}*/
delay (100);
}
}
void inputAction() {
uint8_t buttons = lcd.readButtons();
if (buttons & BUTTON_UP) {
if (currentMenu == 0) {
currentMenu = numofMenus - 1;
} else {
currentMenu--;
}
} else if (buttons & BUTTON_DOWN) {
if (currentMenu == numofMenus - 1) {
currentMenu = 0;
} else {
currentMenu++;
}
} else if (buttons & BUTTON_RIGHT) {
parameters[currentMenu]++;
} else if (buttons & BUTTON_LEFT) {
parameters[currentMenu]--;
}
}
void printScreen() {
lcd.clear();
lcd.print(menu[currentMenu][0]);
lcd.setCursor(0, 1);
lcd.print(parameters[currentMenu]);
lcd.print(" ");
lcd.print(menu[currentMenu][1]);
delay(100);
}
void printtime(int data) {
if (data >= 0 && data < 10) {
lcd.print('0');
}
lcd.print(data);
}
I don't think it is a good strategy to throw all those delays in the code. If you want to work with an RTC, you need to be mindful of those delays as they will affect the functionality of your program. If you don't account for delay properly, they will accumulate as errors. An error of 100 msecs will be seen as error in seconds easily within days.
I did not go through your code because it is hard to understand. I propose you have a look at this code which should be placed in your loop() function:
delay(100);
parameters = parameters + 100;
long rtcSeconds = parameters / 1000;
int seconds = (int) (rtcSeconds % 60); // Range 0 . 59 units: Secs
int minutes = (int)(((rtcSeconds - seconds) / 60) % 60); // Range 0 . 59 units: Mins
int hours = (int) (((rtcSeconds - minutes*60 - seconds) / (3600)) % 24); // Range 0 . 23 units: Hrs
I am using your parameters[0] field to keep track of the time in your syste, in milliseconds units. The field increases every 100 msecs as you see. You can recover the different time values using a combination of the modulus (%) and division operations. Now, I know you need to increase the time in your program. To do so, it is easy:
If you want to increase one second, do this: parameters[0] += 1000;
If you want to increase one minute, do this: parameters[0] += 1000 * 60;
If you want to increase one hour, do this: parameters[0] += 1000 * 3600;
Now, you might need to work with long variables as int have a limited range. You also need to watch for the time roll over when you change your time. If you are decreasing the time, you need to watch pramaters[0] doesn't become negative. In case it does, you need to add 3600 * 24 * 1000 msecs to force it jump one day ahead (3600 * 24 is one day in seconds). I hope you understand this is not a solution to your problem but an alternative approach using a little bit of a simpler code structure.
I'm working on an embedded (avr) project, and basically I want to print out a few different things based on how long a pin has been pressed down. I can't figure out what happens as the value passes through and satisfies if statements along the way (button is still pressed so counter increments).
The setup is as follows:
if overflows is between 7-48 (button pressed for 30ms-200ms), print out a '.'
if overflows is greater than 48 (button pressed for greater than 200ms), print out a '-'
if overflows is greater than 97 (button has not been pressed in over 400ms), print out a ' '
My current code is as follows:
static inline void isr(char type) {
static unsigned int overflows = 0;
static unsigned char idx = 0;
if (type == 'e') { // edge captured
if (TCCR1B & 0x40) { // rising edge
if (overflows < 7) {
// do nothing
} else if (overflows < 49) {
buffer[idx++] = '.';
size++;
} else {
buffer[idx++] = '-';
size++;
}
}
overflows = 0; // restart counting overflows at each edge
} else { // overflow occured
overflows++;
if (buffer[idx-1] != ' ' && !(TCCR1B & 0x40) && overflows > 97) {
buffer[idx++] = ' ';
size++;
}
}
I'm not sure if this is correct though, since it would seem that there would always be a '.' preceding a '-', since as the overflow value is incremented, it satisfies the <49 condition.
Any thoughts?
if you want to count no.of times switch pressed, you can use while loop.
for example,
if(sw==0) //sw is switch connected with I/O pin
{
while(sw==0)
{
led=1; //LED is output
delay(); // use delay function
led=0;
delay();
count++;
}
}
by using while loop, you can avoid from getting multiple times switch pressed. if you make one on and off switch, the count will be increased by one.
I'm not sure if this is correct though, since it would seem that there would always be a '.' preceding a '-', since as the overflow
value is incremented, it satisfies the <49 condition.
But the tests are performed only on the rising edge - when both type == 'e' and (TCCR1B & 0x40) != 0. So the overflow count is evaluated only when the button is released, so you will not see the intermediate . before -.
So to answer your question, a conditional statement or block is executed when the condition is true. Here you have nested conditionals, so all preceding conditions must be true for the inner condition to be evaluated.
According to your description I assume you have a button on your pin, so in this case the first thing what I would recommend before doing anything is to implement a debounce for the button signal.
I would solve the problem something like this:
#define BUTTON_UNKNOWN 0
#define BUTTON_DOWN 1
#define BUTTON_UP 2
#define FALSE 0
#define TRUE 1
static inline unsigned char debounce( unsigned char current_state)
{
static unsigned char ret_value;
unsigned char state_changed = FALSE;
// Counter for number of equal states
static unsigned char count = 0;
// Keeps track of current (de-bounced) state
static unsigned char button_state = 0;
// Check if button is high or low for the moment
if (current_state != button_state)
{
// Button state is about to be changed, increase counter
count++;
if (count >= 3)
{
// The button have not bounced for four checks, change state
button_state = current_state;
// If the button was pressed (not released), tell main so
count = 0;
state_changed = TRUE;
}
}
else
{
state_changed = FALSE;
// Reset counter
count = 0;
}
//if butten press or release detected
if (state_changed == TRUE)
{
//check for the current state of the button
if (current_state != 0)
{
ret_value = BUTTON_DOWN;
}
else
{
ret_value = BUTTON_UP;
}
}
return ret_value;
}
int main(void)
{
//perform proper initialization of your pin
unsigned char button = BUTTON_UNKNOWN;
unsigned char cycle_count = 0;
unsigned char idx = 0;
unsigned char buffer[255];
unsigned char current_state;
unsigned char no_activity;
//unsigned char current_state = (~BUTTON_PIN & BUTTON_MASK) != 0;
while(1)
{
//read the button state
current_state = (~BUTTON_PIN & BUTTON_MASK) != 0;
// Update button_state
button = debounce(current_state);
// Check if the button is pressed.
if (button == BUTTON_DOWN)
{
//count cycles in which the button was pressed
//one cycle is 10 ms - see delay below
cycle_count++;
}
else
{
//check if the button was pressed before
if ((button != BUTTON_UNKNOWN) && (cycle_count != 0))
{
//if button was pressed for 200ms
if (cycle_count <= 20)
{
buffer[idx] = '.';
idx++;
}
else
{
//if the button was pressed between 200 and 400 ms
if ((cycle_count > 20) && (cycle_count <= 40))
{
buffer[idx] = '-';
idx++;
}
//the button was pressed for more than 400ms, uncomment if you need it
/*else
{
buffer[idx] = ' ';
idx++;
}*/
}
//reset counting mechanism
cycle_count = 0;
no_activity = 0;
}
else
{
no_activity++;
if (no_activity >= 40)
{
buffer[idx] = ' ';
idx++;
no_activity = 0;
}
}
}
// Delay for a while so we don’t check to button too often
_delay_ms(10);
}
}
You can adapt this code according to your needs:
change the line current_state = (~BUTTON_PIN & BUTTON_MASK) != 0; so that to read your pin state, and change the declaration of the buffer to suite your needs unsigned char buffer[255];
Please note that due to the debounce the time measured is not exactly 200ms ( it is 200ms + 2*debounce_time = 260ms (debounce time is 3 cycles, each cycle is 10ms, see delay at the end), but you may compensate these errors by reducing the contants in the cycle_count comparisons in the end.
Hope this helps!
If you really stick to your solution, then to avoid the problem what you experience is to not evaluate the overflow value continuously, do not try to determine the length of the button push on the fly, try instead to measure the length of the push and after that evaluate it and put the char in the buffer. You need to wait for the 'release button' and then evaluate how much time the button was pressed. Something like this:
static inline void isr(char type) {
static unsigned int overflows = 0;
static unsigned char idx = 0;
unsiged char button_status;
if (type == 'e') { // edge captured
if (TCCR1B & 0x40) { // rising edge
//perform a debounce otherwise wont be good
button_status = 1;
}
overflows = 0; // restart counting overflows at each edge
} else { // overflow occured
overflows++;
//if button was pressed and its now released evaluate result
if (!(TCCR1B & 0x40) && (button_status == 1))
{
if (overflows < 7) {
// do nothing
} else if (overflows < 49) {
buffer[idx++] = '.';
size++;
} else {
buffer[idx++] = '-';
size++;
}
button_status = 0;
}
if (buffer[idx-1] != ' ' && !(TCCR1B & 0x40) && overflows > 97) {
buffer[idx++] = ' ';
size++;
}
}
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.
void loop() {
photoCell = analogRead(pin);
time = millis();
if (photoCell >= 400){
timeon = millis();
led = 1;
while (analogRead(pin) >= 400) {
timer = millis() - timeon;
//Serial.print("On");
//Serial.println(timer);
}
}
if (photoCell <= 400) {
timeoff = millis();
led = 0;
while (analogRead(pin) <= 400) {
timer2 = millis() - timeoff;
//Serial.print("Off");
//Serial.println(timer2);
}
}
if (timer >= 175 && timer <= 200 && led == 1) {
Serial.print("Char = ");
Serial.println(".");
codearray[i] = 8;
i++;
}
if (timer >= 580 && timer <= 600 && led == 1) {
Serial.print("Char = ");
Serial.println("-");
codearray[i] = 9;
i++;
}
This is my current code which works fine using a photocell plugged into A0 and an led wired into pin 9. The serial monitor displays whether or not I am flashing a dot or dash, morse corde, based on the timing.
However.. When I add this bit of code
if (codearray[0] == 8 && codearray[1] == 8 &&
codearray[2] == 8 && codearray[3] == 0) {
Serial.print("s");
}
The monitor prints nothing. This bit of code fills out an array I set up so I can print back into alphabetical the morse code that was deciphered. I'm pretty sure my logic is correct.
Looking to see if anyone understands why the 2nd bit of code would conflict with the first or what can be wrong with the analog input or serial monitor.
Your question is off topic here; probably belongs on stack overflow.
But it is obvious that you forgot to call Serial.Begin(9600); in setup(); n.b. 9600 is the arduino default baud rate.