I am building a transmitter and receiver pair for two SNES controllers, as I don't like using long extension cords to get the controllers to reach the couch. I'm using ATmega328Ps for the AVRs, with RF24l01 wireless transceivers (using ManiacBugs RF24 library). I am using a modified snesPad library on the transmitter to poll the button states of two controllers and return them as a 32-bit unsigned long, then transmitting that to the receiver. All standard libraries, no issues there (so far).
However, on the receiver side, I have to properly respond to the latch and clock signals from the SNES, and I haven't found any stock libraries for that. For those not familiar with the SNES controllers, they are basically two 8-bit parallel to serial shift registers in series. They latch all of the button states on the rising edge of the latch signal (12 µs pulse high, normally low), drive the first bit on the falling edge of latch, and then drive each successive bit on the rising edge of clock (6 µs delay from fall of latch, normally high, 6 µs low - 6 µs high cycle).
I've decided to use an external interrupt to trigger the proper behavior for the latch pulse and each clock pulse. I'm new to programming Arduinos though, and new to C/C++ as well. Although my code will compile, I'm not certain if it will actually function as intended. If someone who has some experience with AVR's could take a look at my code and let me know if it will work, and if not, where and why, I would be very grateful!
Arduino sketch follows:
/*
Copyright (C) 2012 John Byers <jbyers2#wgu.edu>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 3 as published by the Free Software Foundation
*/
/**
* Dual Wireless Retro Controller Adapter Transmitter
*
* This is the reciever side code for the adapter set.
*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
//
// Hardware Configuration
//
RF24 radio(9,10);
//
// Variable Inits
//
volatile unsigned long state2 = 0xFFFFFFFF;
volatile byte i = 0;
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
int strobe = 2;
int clock = 3;
volatile int data1 = 5;
volatile int data2 = 6;
bool firstLoop = true;
volatile int status2 = 1;
void setup()
{
radio.begin();
radio.setRetries(0,15);
radio.enableDynamicPayloads();
Serial.begin(57600);
pinMode(strobe, INPUT);
pinMode(clock, INPUT);
pinMode(data1, OUTPUT); digitalWrite(data1, LOW);
pinMode(data2, OUTPUT); digitalWrite(data2, LOW);
radio.openWritingPipe(pipes[1]);
radio.openReadingPipe(1,pipes[0]);
//
//Dump the configuration of the RF unit for debugging
//
radio.printDetails();
//
//Setup Interupts
//
attachInterrupt(strobe,latch,RISING);
attachInterrupt(clock,data,RISING);
}
void loop()
{
if (firstLoop) {
int status1 = 1;
bool ok = radio.write( &status1, sizeof(int));
firstLoop = false;
radio.startListening();
if (!ok) {
Serial.println("sync packet transmission failed");
}
else {
Serial.println("sync packet transmission successful");
}
}
if ( radio.available() )
{
unsigned long state = 0;
radio.read( &state, sizeof(unsigned long) );
Serial.println(state, BIN);
state2 = state;
}
else
{
Serial.println("No data recieved yet");
}
}
//Latch interrupt routine
void latch()
{
i = 0;
digitalWrite(data1,HIGH);
digitalWrite(data2,HIGH);
digitalWrite(data1,bitRead(state2,i));
digitalWrite(data2,bitRead(state2,(i+16)));
Serial.println("Bit0 out");
}
//Data interrupt routine
void data()
{
i++;
digitalWrite(data1,bitRead(state2,i));
digitalWrite(data2,bitRead(state2,(i+16)));
Serial.print("Bit");
Serial.print(i);
Serial.println(" out");
if(i=15)
{
digitalWrite(data1,LOW);
digitalWrite(data2,LOW);
radio.stopListening();
int status1 = status2;
bool ok = radio.write( &status1, sizeof(int));
if (!ok) {
Serial.println("sync packet transmission failed");
}
else {
Serial.println("sync packet transmission successful");
}
radio.startListening();
}
}
Related
I am trying to develop a arduino code which runs a stepper motor with C# program via serial communication. I also use Accelstepper library, especially moveTo() and run() functions. I sent maxSpeed and step values as 3500 and 200.000 from C# and motor start to run immediately. I sure that it completes all steps, but after a while, I noticed that stepper motor never reaches its max Speed and it stuck at 3200-3300 range. So because of that finish time is increased. If I give steps more than 200.000, the gap between estimated finish time and real finish time is increased exponentially. If I sent speed as 1000, real speed more or less 970. I have to use acceleration function by the reason of needed torque. Then I search the problem and some people said that it occurs because of Accelstepper library which consist run() function and other stuff that I wrote in the loop section. Especially I could not ensure the reason of the problem is Arduino, AccelStepper library or code that I wrote. Can you please help me to solve problem?
NOTE: Arduino Mega 2560 is used.
Arduino code is below:
#include <AccelStepper.h>
#include <stdio.h>
#define STEP_PIN_C 5 //31
#define DIRECTION_PIN_C 23 //32
#define ENABLE_PIN_C 24 //33
#define SET_ACCELERATION 600.0
AccelStepper stepper(1, STEP_PIN_C, DIRECTION_PIN_C);
unsigned long oldTime=0;
unsigned long now;
float newSpeed;
float maxSpeed = 3500.0;
bool newDataBit, runAllowed = false,addingProg=false,mainProg=false;
char commandChar;
long currentPosition;
long int steps = 0, mainNewStep, addedNewStep,memMainStep;
void checkSerial();
void checkRunning();
void stopMotor();
void runMotor();
void sendInfo();
const unsigned long delayTime = 1000;
unsigned long timer;
int count = 0;
bool running = false;
void setup()
{
Serial.begin(9600);
pinMode(ENABLE_PIN_C, OUTPUT);
digitalWrite(ENABLE_PIN_C, HIGH);
stepper.setCurrentPosition(0); //initial value
stepper.setMaxSpeed(0.0); //initial value
stepper.setAcceleration(SET_ACCELERATION); //initial value
}
void loop()
{
sendInfo();
checkRunning();
checkSerial();
}
void checkRunning()
{
if (runAllowed == true)
{
if (stepper.distanceToGo() == 0)
{
stopMotor();
checkSerial();
}
else
{
runMotor();
checkSerial();
}
}
}
void checkSerial()
{
if (Serial.available())
{
newDataBit = true;
commandChar = Serial.read();
}
if (newDataBit == true)
{
///DoStuff depends on what is received as commandChar via serial port
mainProgram(stepper.currentPosition(),newSpeed,mainNewStep);
newDataBit = false;
}
}
void runMotor(){
digitalWrite(ENABLE_PIN_C, LOW);
stepper.run();
running = true;
}
void stopMotor(){
stepper.setCurrentPosition(0);
digitalWrite(ENABLE_PIN_C, HIGH);
stepper.stop();
running = false;
timer = millis() + delayTime;
}
void mainProgram(long currentPositionValue,float maxSpeedValue,long stepValue)
{
mainProg = true;
if (stepper.distanceToGo() == 0) //YOLUMU TAMAMLADIM
{
addingProg = false;
steps = stepValue;
stepper.setCurrentPosition(currentPositionValue);
//stepper.setSpeed(0);
stepper.setMaxSpeed(maxSpeedValue);
stepper.moveTo(steps);
}
else
{
steps = stepValue + steps;
stepper.setCurrentPosition(currentPositionValue);
//stepper.setSpeed(0);
stepper.setMaxSpeed(newSpeed);
stepper.moveTo(steps);
}
}
void sendInfo(){
now = millis();
if(now-oldTime > 1000){ //saniyede 1
Serial.print(stepper.currentPosition());
Serial.print(" ");
Serial.print(stepper.isRunning());
Serial.print(" ");
Serial.println(stepper.speed());
oldTime = now;
}
}
From AccelStepper documentation:
The fastest motor speed that can be reliably supported is about 4000
steps per second at a clock frequency of 16 MHz on Arduino such as Uno
etc.
This is if you do nothing else but running the stepper.
You check your serial interface and send multiple lines every second. Both is quite expensive.
I am trying to implement error correction over an r/f communication between two arduinos. I tried adding a timer to it, in order to create a packet resend, but whenever it gets past the first send, it starts printing garbage ad infinity instead of doing the timer interrupt.
I tried messing around with the inside loop conditions some as well as trying to figure out what was wrong with the timer, but I couldn't figure it out. The problem seems to happen right around the first serial print, which is strange, because that part of the code is mostly unchanged.
(packets is a structure of two ints)
#include <ELECHOUSE_CC1101.h>
#include "packets.h"
// These examples are from the Electronics Cookbook by Simon Monk
// Connections (for an Arduino Uno)
// Arduino CC1101
// GND GND
// 3.3V VCC
// 10 CSN/SS **** Must be level shifted to 3.3V
// 11 SI/MOSI **** Must be level shifted to 3.3V
// 12 SO/MISO
// 13 SCK **** Must be level shifted to 3.3V
// 2 GD0
const int n = 61;
unsigned short int sequence = 0;
byte buffer[n] = "";
void setup() {
Serial.begin(9600);
Serial.println("Set line ending to New Line in Serial Monitor.");
Serial.println("Enter Message");
ELECHOUSE_cc1101.Init(F_433); // set frequency - F_433, F_868, F_965 MHz
// initialize timer1
noInterrupts(); // disable all interrupts
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 0xFFFF; // Max value for overflow for now
TCCR1B |= (1 << CS12); // 256 prescaler
interrupts(); // enable all interrupts
}
Packet pckt, recieve;
ISR(TIMER1_OVR_vect){ // timer compare interrupt service routine
//Resend packet
ELECHOUSE_cc1101.SendData(buffer, pckt.data + pckt.seqNum);
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
buffer[len] = '\0';
recieve.seqNum = buffer[n];
Serial.println("Interrupt");
}
void loop() {
if (Serial.available()) {
pckt.data = Serial.readBytesUntil('\n', buffer, n);
pckt.seqNum = sequence;
buffer[pckt.data] = '\0';
buffer[n-1] = pckt.seqNum;
Serial.println((char *)buffer);
ELECHOUSE_cc1101.SendData(buffer, pckt.data + pckt.seqNum);
TCNT1 = 0; // clear timer
TIMSK1 |= (1 << TOIE0); // enable timer compare interrupt
int len = ELECHOUSE_cc1101.ReceiveData(buffer);
while (recieve.seqNum <= sequence) {
}
TIMSK1 &= ~(1 << TOIE0); // turn off the timer interrupt
}
}
Sending data takes too long for interrupts. You should keep calls to send and receive buffers of data within the loop() function call tree. For example, sending a 12 bytes message via UART at 9600 bauds can take up to about 12ms.
You can use the timer interrupt to decrement a timeout counter, as is usually done on micro controllers, or use the millis() function to handle timings, as is easily done on Arduino.
I suggest you use the millis() function to compute timeouts.
example:
/* ... */
// I could not figure out what you were trying to do with
// pckt.seqNum.... Putting it at the end of the buffer
// makes no sense, so I've left it out.
// Moreover, its size is 2, so placing it at buffer[n-1] overflows the buffer...
enum machineState {
waitingForSerial,
waitingForResponse,
};
unsigned int time_sent; // Always use unsigned for variables holding millis()
// can use unsigned char for timeouts of 255
// milliseconds or less. unsigned int is good for about
// 65.535 seconds or less.
machineState state = waitingForSerial;
void loop()
{
switch(state)
{
case waitingForSerial:
pckt.data = Serial.readBytesUntil('\n', buffer, sizeof(buffer));
if (pckt.data > 0)
{
++pckt.seqNum;
Serial.write(buffer, pckt.data);
ELECHOUSE_cc1101.SetReceive();
ELECHOUSE_cc1101.SendData(buffer, pckt.data);
time_sent = millis();
state = waitingForResponse;
}
break;
case waitingForResponse:
if (ELECHOUSE_cc1101.CheckReceiveFlag())
{
auto len = ELECHOUSE_cc1101.ReceiveData(buffer)) // can use C++17 with duinos!!!
Serial.print("cc1101: ");
Serial.write(buffer, len);
state = waitingForSerial; // wait for another command from PC
}
// 1 second timeout, note the cast and subtraction, this is to avoid any
// issues with rollover of the millis() timestamp.
else if ((unsigned int)millis() - time_sent > 1000)
{
// resend ... stays stuck this way.
Serial.println("Retrying :(");
ELECHOUSE_cc1101.SendData(buffer, pckt.data);
time_sent = millis();
}
break;
default:
state = waitingForSerial;
Serial.println("unhandled state");
break;
}
}
I am using Arduino for the first time, my project consists of RF transmitter connected with arduino UNO and a RF receiver connected to Arduino Mega.
I'm try to send data from transmitter and print it on receiver serial using VirtualWire library and every thing is okey for this receiver code:
#include <VirtualWire.h>
int x=9;
int y=8;
int z=10;
int r=7;
void setup()
{
Serial.begin(9600);
pinMode(x,OUTPUT);
pinMode(y,OUTPUT);
pinMode(z,OUTPUT);
pinMode(r,OUTPUT);
vw_setup(2000);
vw_rx_start();
}
void loop()
{
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen)) // Non-blocking
{
int i;
// Message with a good checksum received, print it.
Serial.print("Got: ");
for (i = 0; i < buflen; i++)
{
Serial.print(buf[i], HEX);
Serial.print(' ');
}
Serial.println();
}
}
Then i add some if statments to run 2 motors (connected to x,y,z,r pins) based on recrived values :
#include <VirtualWire.h>
int x=9;
int y=8;
int z=10;
int r=7;
void setup()
{
Serial.begin(9600);
pinMode(x,OUTPUT);
pinMode(y,OUTPUT);
pinMode(z,OUTPUT);
pinMode(r,OUTPUT);
vw_setup(2000);
vw_rx_start();
}
void loop()
{
uint8_t buf[VW_MAX_MESSAGE_LEN];
uint8_t buflen = VW_MAX_MESSAGE_LEN;
if (vw_get_message(buf, &buflen)) // Non-blocking
{
int i;
// Message with a good checksum received, print it.
Serial.print("Got: ");
for (i = 0; i < buflen; i++)
{
if (buf[i]==0x77)//Stop motors
{
digitalWrite(x,LOW);
digitalWrite(y,LOW);
digitalWrite(z,LOW);
digitalWrite(r,LOW);
}
else
{
if(buf[i]==0x80)//2 motors clockwise
{
digitalWrite(x,LOW);
digitalWrite(y,HIGH);
digitalWrite(z,HIGH);
digitalWrite(r,LOW);
}
if (buf[i]==0x90)//counter clockwise
{
digitalWrite(x,HIGH);
digitalWrite(y,LOW);
digitalWrite(z,LOW);
digitalWrite(r,HIGH);
}
}
}
Now the problem is that when motors is stop working and I am sending the values that will run it either with or counterclockwise the motor works in the right direction but then does not respond to any data sent.
In short, when the motor stops working and I send data, the receiver receives the values and runs the motor violin is required, but then for example if the motor was working clockwise and sent the order which is running counterclockwise or even stop work, it does not respond and continues to move It was.
I noticed that this bacause when motors runs this function returns false
vw_get_message(buf, &buflen)
But i don't no why!
In VirtualWire library every time you send a new character or a set of characters your buffer will be overwritten. So the problem in this program is with your for loop checking. It will work fine if you just use the following
For example if you are sending characters like 'A', 'B' etc then
if (vw_get_message(buf, &buflen))
{
if(buf[0]=='A')
{
//move forward
}
if(buf[0]=='B')
{
//move backward
}
.... and so on
Hope this helps
I have an OPT101 connected to a slave arduino to measure light intensity. I want to send the data received from the OPT101 circuit to a master arduino that will print the data on the serial monitor. When I test my code, nothing shows up on the screen. (I know it's not my i2c connection cause I tested it by sending "hello"). I am using an arduino leonardo as the slave and the arduino uno as the master.
The code for the OPT101 circuit is:
#define inPin0 0
void setup() {
Serial.begin(9600);
Serial.println();
}
void loop() {
int pinRead0 = analogRead(inPin0);
double pVolt0 = pinRead0 / 1024.00 * 5.0;
Serial.print(pVolt0, 4 );
Serial.println();
delay(100);
}
I tired to combine the slave code and my OPT101 code to get this:
#include
#define inPin0 0
void setup() {
Wire.begin(2);
}
void loop() {
Wire.beginTransmission(2);
Wire.onRequest(requestEvent);
Wire.endTransmission();
}
void requestEvent()
{
int pinRead0 = analogRead(inPin0);
int pVolt0 = pinRead0 / 1024.0 * 5.0;
Wire.write((byte)pVolt0);
}
And this is my master code:
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(14400);
Wire.requestFrom(2, 8);
while(Wire.available())
{
char c = Wire.read();
Serial.print(c);
}
}
void loop()
{
}
You must follow steps described below to communicate between master and slave I2C devices:
Only master can initiate read or write request.
Read or write requests must be synchronous. It means, slave can only return data after master requests for them and vice versa for write.
Do not use slave address from 0 - 7. They are reserved. Use slave address that ranges between 8 to 127.
On Arduino I2C, you can only send and receive a byte. To send or receive integer, double that have multiple bytes, you need to split them first and on other side, you have to combine them into its equivalent datatype. (Correct me, if I'm wrong.)
Your code should be like this:
Master Sketch:
#include <Wire.h>
#define SLAVE_ADDRESS 0x40
// This macro reads two byte from I2C slave and converts into equivalent int
#define I2C_ReadInteger(buf,dataInteger) \
buf[0] = Wire.read(); \
buf[1] = Wire.read(); \
dataInteger = *((int *)buf);
// Returns light intensity measured by 'SLAVE_ADDRESS' device
int GetLightIntensity()
{
byte Temp[2];
int Result;
// To get integer value from slave, two are required
int NumberOfBytes = 2;
// Request 'NumberOfBytes' from 'SLAVE_ADDRESS'
Wire.requestFrom(SLAVE_ADDRESS, NumberOfBytes);
// Call macro to read and convert bytes (Temp) to int (Result)
I2C_ReadInteger(Temp, Result);
return Result;
}
void setup()
{
// Initiate I2C Master
Wire.begin();
// Initiate Serial communication # 9600 baud or of your choice
Serial.begin(9600);
}
void loop()
{
// Print light intensity at defined interval
Serial.print("Light Intensity = ");
Serial.println(GetLightIntensity());
delay(1000);
}
Slave Sketch:
#include <Wire.h>
#define SLAVE_ADDRESS 0x40
#define inPin0 0
// Preapres 2-bytes equivalent to its int
#define IntegerToByte(buf,intData) \
*((int *)buf) = intData;
// Sends int to Master
void I2C_SendInteger(int Data)
{
byte Temp[2];
// I2C can only send a byte at a time.
// Int is of 2bytes and we need to split them into bytes
// in order to send it to Master.
// On Master side, it receives 2bytes and parses into
// equvivalent int.
IntegerToByte(Temp, Data);
// Write 2bytes to Master
Wire.write(Temp, 2);
}
void setup()
{
// Initiate I2C Slave # 'SLAVE_ADDRESS'
Wire.begin(SLAVE_ADDRESS);
// Register callback on request by Master
Wire.onRequest(requestEvent);
}
void loop()
{
}
//
void requestEvent()
{
// Read sensor
int pinRead0 = analogRead(inPin0);
int pVolt0 = pinRead0 / 1024.0 * 5.0;
// Send int to Master
I2C_SendInteger(pVolt0);
}
This code is tested on Arduino Version: 1.6.7.
For more information regarding I2C communication, refer Arduino
Example: Master Reader
Why are you putting the while loop in the setup() function instead of using the loop() function ?
But more confusing is this line int pVolt0 = pinRead0 / 1024.0 * 5.0;. In the initial code the variable is not int but double. I suggest you try to recode using the original line:
double pVolt0 = pinRead0 / 1024.00 * 5.0;
And only then reduce to int.
In Arduino I2C, you can only send and receive one byte, and it is necessary to combine them in their equivalent data type.
I am using MPlab to read data from a pic micro controller. I am using pic18F87J11.
The data that I want to read is on pin 3 of the DB9 of the RS232, and my RS232 is connected to the pic micro controller.
Can anyone help me or give me a simple sample code to do that??
Thank you,
//
// Designed by www.MCUExamples.com
// rasika0612#gmail.com
// Serial communications example. Echo data comes to serial port
// using serial receive interrupt.
//
#include <p18f4520.h>
#pragma config OSC = HS // 20MHz Crystal, (HS oscillator)
#pragma config PBADEN = OFF // PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config WDT = OFF // watch dog timer off
#pragma config LVP = OFF // Low voltage program off
unsigned char cUART_char;
unsigned char cUART_data_flg;
void init_uart(void);
void UART_putc(unsigned char c);
void InterruptHandlerLow ();
void main()
{
init_uart(); // init UART module
while (1) // infinite loop which handles ncoming data as they arrive
{
if (cUART_data_flg==1)// if new data available, send it back through USART tx line (echo it)
{
UART_putc(cUART_char);
cUART_data_flg=0; // clear new data flag so one charactor will echoed once
}
}
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
#pragma code InterruptVectorLow = 0x18
void InterruptVectorLow (void)
{
_asm
goto InterruptHandlerLow //jump to interrupt routine
_endasm
}
//----------------------------------------------------------------------------
// Low priority interrupt routine
#pragma code
#pragma interrupt InterruptHandlerLow
void InterruptHandlerLow ()
{
if (PIR1bits.RCIF==1)//is interrupt occured by EUSART receive?,
//then RCREG is full we have new data (cleared when RCREG is read)
{
if(RCSTA&0x06) //more efficient way than following commented method to check for reception error
//if(RCSTAbits.FERR==1 || RCSTAbits.OERR==1 )
{
RCSTAbits.CREN=0; //Overrun error (can be cleared by clearing bit CREN)
cUART_char=RCREG; //clear Framing error
RCSTAbits.CREN=1;
}
else
{
cUART_char = RCREG; // read new data into variable
cUART_data_flg = 1; // new data received. so enable flg
}
}
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
void init_uart(void) // init UART module for 9600bps boud, start bit 1, stopbit 1, parity NONE
{
cUART_data_flg=0; // init data receive flag to zero (no data)
TRISCbits.TRISC7=1; //Make UART RX pin input
TRISCbits.TRISC6=0; //Make UART TX pin output
SPBRGH = 0x02; //9600bps 20MHz Osc
SPBRG = 0x08;
RCSTAbits.CREN=1; //1 = Enables receiver
RCSTAbits.SPEN=1; //1 = Serial port enabled (configures RX/DT and TX/CK pins as serial port pins)
BAUDCONbits.BRG16=1;//1 = 16-bit Baud Rate Generator – SPBRGH and SPBRG
TXSTAbits.SYNC=0; //0 = Asynchronous mode
TXSTAbits.BRGH=1; //1 = High speed
TXSTAbits.TXEN=1; //1 = Transmit enabled
RCONbits.IPEN = 1; //enable Interrupt priority levels
IPR1bits.RCIP=0; // EUSART Receive Interrupt Priority 0 = Low priority
PIE1bits.RCIE=1; // 1 = Enables the EUSART receive interrupt
INTCONbits.GIEL = 1;//enable interrupts
INTCONbits.GIEH = 1;
}
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
void UART_putc(unsigned char c)
{
TXSTAbits.TXEN=0;// disable transmission
TXREG=c; // load txreg with data
TXSTAbits.TXEN=1; // enable transmission
while(TXSTAbits.TRMT==0) // wait here till transmit complete
{
Nop();
}
}