Bike pedaling boring lesson. In order to make the process more interesting, I decided to connect it to a PC for the ability to play various computer games simulators. We pedal and drive for example a truck.
Speed depends on the speed of the pedals. For braking it is necessary to pedal back. To determine the speed and direction of rotation of the pedals, 2 Hall sensors are used.
18 pairs of niode magnets are glued on the cadence disc. The project is assembled on two Arduino Micro and Arduino Nano boards.
Arduino Micro programmed as a dual-axis joystick with 15 buttons. Arduino Nano used as a port expander. Communication is via the SPI bus. Installation is made on a breadboard for soldering.
The speed of pedaling and the maximum steering angle are carried out using potentiometers.
#include <SPI.h>
#include <Wire.h>
#include "spi_master.h"
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Joystick.h>
Adafruit_SSD1306 display(128, 32, &Wire, -1);
Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD,
15, 0, // Button Count, Hat Switch Count
true, true, false, // X and Y, but no Z Axis
false, false, false, // No Rx, Ry, or Rz
false, false, // No rudder or throttle
false, false, false); // No accelerator, brake, or steering
int16_t X = 0; //
int16_t XL = 0; //
int16_t XR = 0; //
int16_t XF = 0; // X ()
int16_t XLm = 490; //
int16_t XRm = 500; //
int16_t wheelAngle = 0; //
int8_t Y = 0;
// , ,
uint8_t hours = 0;
uint8_t minutes = 0;
uint8_t seconds = 0;
// long
long previousMillis = 0; //
long interval = 1000; // / (1 )
long lastTime = 0;
void setup (void)
{
mater_init();
//
Serial.begin (9600);
Serial.println ();
//
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
pinMode(10, INPUT_PULLUP);
pinMode(11, INPUT_PULLUP);
// ( - )
pinMode(13, OUTPUT);
master_arr [0] = 0; // n/a
master_arr [1] = 0; // n/a
master_arr [2] = 0; // n/a
// ( )
Joystick.begin(false);
Joystick.setYAxisRange(-64, 64);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}
void loop (void)
{
refreshSPI ();
unsigned long currentMillis = millis();
// ,
if (currentMillis - previousMillis > interval) {
//
previousMillis = currentMillis;
//... lastTime +1
lastTime = millis();
seconds++;
// 60, +1...
if (seconds >= 60) {
seconds = 0;
minutes++;
}
// ... ...
if (minutes >= 60) {
minutes = 0;
hours++;
}
// ...
if (hours >= 24) {
hours = 0;
}
}
//
if (!digitalRead(7)&&!digitalRead(4)) {
seconds = 0;
minutes = 0;
hours = 0;
}
// /
digitalWrite(13, bitRead(slave_arr [1], 7));
wheelAngle = map(analogRead(A5), 2, 1020, 90, 20);
wheelAngle = wheelAngle * 10;
Joystick.setXAxisRange(-wheelAngle / 2, wheelAngle / 2);
X = map(analogRead(A0), 0, 1023, 1023, 0);
XL = map(analogRead(A1), 470, 720, 0, 350);
if (XL < 0) XL = 0;
if (XL > 350) XL = 350;
XR = map(analogRead(A2), 580, 340, 0, 350);
if (XR < 0) XR = 0;
if (XR > 350) XR = 350;
if (X >= XLm && X <= XRm) {
//
XF = 0;
} else if (X > XRm) {
//
int16_t x = X - XRm;
if (x > 300)x = 300;
XF = x / 3;
} else if (X < XLm) {
//
int16_t x = X - XLm;
if (x < -292) x = -300;
XF = x / 3;
}
XF = XF + XR - XL;
Y = slave_arr [0];
//
if (!digitalRead(10)) Joystick.pressButton (0); else Joystick.releaseButton (0); // rudder BT1
if (!digitalRead(11)) Joystick.pressButton (1); else Joystick.releaseButton (1); // rudder BT2
if (!digitalRead(9)) Joystick.pressButton (2); else Joystick.releaseButton (2); // rudder BT3
if (!digitalRead(8)) Joystick.pressButton (3); else Joystick.releaseButton (3); // rudder BT4
if (!digitalRead(7)) Joystick.pressButton (4); else Joystick.releaseButton (4); // rudder BT5
if (!digitalRead(5)) Joystick.pressButton (5); else Joystick.releaseButton (5); // rudder BT6
if (!digitalRead(6)) Joystick.pressButton (6); else Joystick.releaseButton (6); // rudder BT7
if (!digitalRead(4)) Joystick.pressButton (7); else Joystick.releaseButton (7); // rudder BT8
if (bitRead(slave_arr [1], 0)) Joystick.pressButton (8); else Joystick.releaseButton (8); // rudder BT9
if (bitRead(slave_arr [1], 1)) Joystick.pressButton (9); else Joystick.releaseButton (9); // rudder BT10
if (bitRead(slave_arr [1], 2)) Joystick.pressButton (10); else Joystick.releaseButton (10); // rudder BT11
if (bitRead(slave_arr [1], 3)) Joystick.pressButton (11); else Joystick.releaseButton (11); // rudder BT12
if (bitRead(slave_arr [1], 4)) Joystick.pressButton (12); else Joystick.releaseButton (12); // rudder BT13
if (bitRead(slave_arr [1], 5)) Joystick.pressButton (13); else Joystick.releaseButton (13); // rudder BT14
if (bitRead(slave_arr [1], 6)) Joystick.pressButton (14); else Joystick.releaseButton (14); // rudder BT15
Joystick.setXAxis(XF);
Joystick.setYAxis(Y);
Serial.println(XL);
//Serial.print('=');
//Serial.println(XF);
//
display.clearDisplay();
display.setTextSize(2); // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE); // Draw white text
display.setCursor(0, 0); // Start at top-left corner
display.print(XF);
display.setCursor(64, 0); // Start at top-left corner
display.print(Y);
if (!digitalRead(13)) {
// -
// X
display.setTextSize(1);
display.setCursor(0, 16);
display.print (wheelAngle);
// Y
display.setCursor(64, 16);
//
display.print(slave_arr [2]);
//
display.setCursor(64, 24);
display.print(slave_arr [3]);
} else {
// -
display.setTextSize(2);
display.setCursor(0, 16);
if (hours < 10) display.print(0);
display.print(hours);
display.print(':');
if (minutes < 10) display.print(0);
display.print(minutes);
display.print(':');
if (seconds < 10) display.print(0);
display.print(seconds);
}
display.display();
//
Joystick.sendState();
}
// Arduino UNO, NANO, Leonardo
// SPI
// 13 - SCK, 12 - MISO, 11 - MOSI, 10 - SS
// SCK, MI, MO, SS Leonardo
//
//
//
//
uint8_t master_arr [4];
//
uint8_t slave_arr [4];
void mater_init(){
digitalWrite(SS, HIGH); // ensure SS stays high for now
SPI.begin ();
//
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
void refreshSPI () //
{
digitalWrite(SS, LOW); // enable Slave Select
// "" slave_arr[]
SPI.transfer (0xFF);
//
delayMicroseconds (20);
// master_arr[]
for (uint8_t i = 0; i < sizeof(master_arr); i++) {
slave_arr[i] = SPI.transfer(master_arr[i]);
//
delayMicroseconds (20);
}
digitalWrite(SS, HIGH); // disable Slave Select
} // end of refreshSPI
#include "spi_slave.h"
volatile uint8_t filter = 0; //
volatile uint32_t fDisk18 = 0; // /18
volatile uint32_t bDisk18 = 0; // /18
volatile uint32_t OLDfDisk18 = 0; // /18
volatile uint32_t OLDbDisk18 = 0; // /18
volatile uint32_t startTime = 0; //
volatile uint32_t endTime = 0; // 1/18
boolean buttonWasUp = true; // BTSet ?
void setup (void)
{
slave_init(); // SPI SLAVE
pinMode (2, INPUT_PULLUP); // yellow hall
pinMode (3, INPUT_PULLUP); // green hall
pinMode (4, OUTPUT); // yellow LED !!!
pinMode (5, OUTPUT); // green LED !!!
// D
bitSet(PCICR, 2);
// 2 3
bitSet(PCMSK2, 2);
bitSet(PCMSK2, 3);
slave_arr [0] = 0; // / int8_t
slave_arr [1] = 0; //
slave_arr [2] = 255; //
slave_arr [3] = 0; // Y
pinMode (14, INPUT_PULLUP); // BT9
pinMode (15, INPUT_PULLUP); // BT10
pinMode (16, INPUT_PULLUP); // BT11
pinMode (17, INPUT_PULLUP); // BT12
pinMode (9, INPUT_PULLUP); // BT13
pinMode (8, INPUT_PULLUP); // BT14
pinMode (7, INPUT_PULLUP); // BT15
pinMode (6, INPUT_PULLUP); // BTSet
}
ISR (PCINT2_vect) { // D0..D7
//
if (!bitRead(slave_arr [1], 7)) {
bitWrite(PORTD, 4, bitRead(PIND, 2));
bitWrite(PORTD, 5, bitRead(PIND, 3));
}
filter = filter << 1;
bitWrite(filter, 0, bitRead(PIND, 2));
filter = filter << 1;
bitWrite(filter, 0, bitRead(PIND, 3));
// 2,3 B10110100
if (filter == B10110100) {
//
OLDfDisk18 = fDisk18;
//
fDisk18++;
endTime = millis() - startTime;
startTime = millis();
}
// 2,3 B10000111
if (filter == B10000111) {
//
OLDbDisk18 = bDisk18;
//
bDisk18++;
endTime = millis() - startTime;
startTime = millis();
}
//
if (endTime>255) endTime = 255;
}
void loop (void)
{
if (digitalRead (SS) == HIGH) countSPIb = -1; //
// 0 / 1
boolean buttonIsUp = digitalRead(6);
// (&&) ...
if (buttonWasUp && !buttonIsUp) {
delay(10);
//
buttonIsUp = digitalRead(6);
if (!buttonIsUp) { // ...
// ... ! 0 / 1
bitWrite(slave_arr [1], 7, !bitRead(slave_arr [1], 7));
}
}
//
buttonWasUp = buttonIsUp;
//
bitWrite(slave_arr [1], 0, !digitalRead(14)); // BT9
bitWrite(slave_arr [1], 1, !digitalRead(15)); // BT10
bitWrite(slave_arr [1], 2, !digitalRead(16)); // BT11
bitWrite(slave_arr [1], 3, !digitalRead(17)); // BT12
bitWrite(slave_arr [1], 4, !digitalRead(9)); // BT13
bitWrite(slave_arr [1], 5, !digitalRead(8)); // BT14
bitWrite(slave_arr [1], 6, !digitalRead(7)); // BT15
//
slave_arr [3] = map(analogRead(A7),0,1023,1,254);
//
if (millis() - startTime > 255) {
slave_arr[0] = 0;
endTime = 255;
}
if (OLDfDisk18 != fDisk18) { //
OLDfDisk18 = fDisk18; //
if (endTime < slave_arr [3]) slave_arr [0] = 64;
else slave_arr [0] = map(endTime, 255, slave_arr [3], 0, 64);
}
if (OLDbDisk18 != bDisk18) { //
OLDbDisk18 = bDisk18; //
if (endTime < slave_arr [3]) slave_arr [0] = -64;
else slave_arr [0] = map(endTime, 255, slave_arr [3], 0, -64);
}
//
slave_arr [2] = endTime;
}
//
// Serial.begin(9600);
//long previousMillis = 0; //
//long interval = 100; //
/*
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval) {
//
previousMillis = currentMillis;
int8_t testik = slave_arr [0];
Serial.println(slave_arr [3]);
}
*/
// ATmega328P
// Arduino UNO, NANO
// SPI
// 13 - SCK, 12 - MISO, 11 - MOSI, 10 - SS
//
//
//
//
volatile uint8_t master_arr [4];
//
volatile uint8_t slave_arr [4];
//
volatile int16_t countSPIb = -1;
void slave_init(){
// SPI SLAVE
DDRB|=(1<<PB4); // MISO
SPCR |= (1 << SPIE)|(1 << SPE); // SPI SLAVE
}
ISR (SPI_STC_vect) // SPI -
{
if (countSPIb < 0) { // ""
countSPIb++; //
SPDR = slave_arr [countSPIb]; //
return; //
}
master_arr [countSPIb] = SPDR; //
countSPIb++; //
SPDR = slave_arr [countSPIb]; // (+1 )
if (countSPIb >= sizeof(master_arr)) { //
countSPIb = -1; //
}
} // SPI -
// ATmega328P
// Arduino UNO, NANO
// SPI
// 13 - SCK, 12 - MISO, 11 - MOSI, 10 - SS
//
//
//
//
volatile uint8_t master_arr [4];
//
volatile uint8_t slave_arr [4];
//
volatile int16_t countSPIb = -1;
void slave_init(){
// SPI SLAVE
DDRB|=(1<<PB4); // MISO
SPCR |= (1 << SPIE)|(1 << SPE); // SPI SLAVE
}
ISR (SPI_STC_vect) // SPI -
{
if (countSPIb < 0) { // ""
countSPIb++; //
SPDR = slave_arr [countSPIb]; //
return; //
}
master_arr [countSPIb] = SPDR; //
countSPIb++; //
SPDR = slave_arr [countSPIb]; // (+1 )
if (countSPIb >= sizeof(master_arr)) { //
countSPIb = -1; //
}
} // SPI -
Comments