So I have to write a code that recognizes colour using a colour-detector.
The because the colourpalette is limited to just 6 colours I can be saved as an Integer (Red as 0, Green as 1 aso.).
Now I have problems transfering the Integer from the Arduino that handles the detector to the Arduino I have to write code on.
I tried using the analog (A0) pin but with that I only ended up with a 19-20 whenever I tried to transfer anything at all.
Is there a solution to transfer an Integer from 0-5?
Thanks in advance
Using the Analog is not a good solution. You should use the "Serial Connection". It only requires two cables - no other electronics - and the code is very simple (see below).
If you just want to transfer values in the range 0-255 or smaller (as in your case: 0-5), you can use the "byte"-type variable. One or multiple bytes can easily be transferred using a serial connection, using the "TX" (transmit) and "RX" (receive) pins of the Arduinos. You just connect the TX pin from Arduino #1 to the "RX" pin of Arduino #2 - and: connect the GND pins of the two.
In the setup code for both, you need to start the serial connection with the same baud rate, e.g.
void setup(){
Serial.begin(9600);
}
Arduino #1 is sending a byte using the following command:
byte color = 0; // declare the variable "color"
color = 3; // set the variable to any value in the range [0-255]
Serial.write(color); // transmit the byte-variable "color"
Arduino #2 is receiving the byte. Therefore it needs to continuously check for new serial data.
void loop() {
byte data = 0;
// - check for new serial data - and respond accordingly
if (Serial.available() > 0) {
int x = Serial.read(); // The "Serial.read" command returns integer-type
data = x; //
// - now: do something with "data"
if (data == 0) {
// "red" was received ... do something ...
} else if (data == 1) {
// "green" was received ... do something ...
} else if (data == 2) {
// ... and so on, and so on ...
}
}
// ... do other tasks
}
Make sure that in the "other tasks" you are not using the command "delay", as this would prevent your code from checking the serial for new data in a timely manner.
In exactly the same way, your Arduino #2 could also send data back to Arduino #1. In that case, you add one more cable connecting "TX" from #2 to "RX" of #1, and use the same code as above, on the respective other Arduino.
Serial is most universal, as you can test/simulate/use it by a broad variety of partners.
Here, you might code your possible values as human readable characters { '0' .. '5' } or
{'R', 'G', 'B', 'C', 'M', 'Y'} or whatever you like.
Eventually, I2C is a better way of serial communication.
Of course, an analog signal can be divided into 6 clearly distinguishable areas, if it's more about states than about events. You need electronics (low pass filter) to turn analogWrite PWM into analog constant values. And eventually, you have to handle the state transitions separately.
(Huh, sounds pretty complicated, doesn't it :) )
Related
I would like your help to solve the following problem.
I'm using an ESP32 Dev Kit V1 connected as follows:
Pin 4 (input) is connected to a 20kHz and 3.3V signal and to channel 1 of the oscilloscope; and
Pin 2 (output) is connected to channel 2 of the oscilloscope.
My goal is to use interrupts and generate a signal on pin 2 (output) that follows the variations of the signal on pin 4 (input).
The image below illustrates two behaviors. The most frequent and the other one that happens occasionally.
In the first behavior, the latency is around 3 us, but sometimes there is a variation (jitter) and the rise of the output signal takes 15 us or even more to keep up with the input.
I would like to know how to remove this occasional behavior and keep the system stable.
The code that I'm using is below. To compile and upload I am using the latest Arduino IDE version 1.8.13.
I'm using GPIO.out_w1ts and GPIO.out_w1tc because I believe it will be faster than using digitalWrite(pin, state).
Also notice that I'm not reading the state of pin 4 (input) to be faster, because of this, sometimes the output signal gets inverted, but that's not a problem at this point.
#define OUTPUT_PIN 2
#define INPUT_PIN 4
volatile bool state = false;
void IRAM_ATTR interruptFunction() {
if (state)
GPIO.out_w1ts = 0b100;
else
GPIO.out_w1tc = 0b100;
state = !state;
}
void setup() {
pinMode(INPUT_PIN, INPUT);
attachInterrupt(digitalPinToInterrupt(INPUT_PIN), interruptFunction, CHANGE);
gpio_config_t io_conf;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = 0b100;
gpio_config(&io_conf);
}
void loop() {
}
The settings used in the Arduino IDE are illustrated in the next image.
Thanks in advance for all the help!
I am fairly new to the arduino topic and try to get a few things to work together.
First i tried setting up a DC motor that can be controlled via PWM, which works perfectly when used standalone. I can start/stop the motor and change speed depending on the value i send to the PWM pin.
Second i tried to use an RF-5V wireless receiver to work with a remote control from remote switched power outlets. For this one i followed the instructions on how to build a 433mhz sniffer.
This all by itself works as well. I can receive diffent codes depending on which keys on the remote i am pressing.
Now the fun part started: I wanted to integrate both of the projects into one, so i could use the remote to start/stop the motor.
So i came up with the following circuit:
(Thanks for some of you pointing out that the circuit does not match the sketch. I made an error when drawing, but even with the cables attached to the right pins, it works as described)
and the following code (which is partly from the instructions mentioned above):
#include <RCSwitch.h>
// init 433MHz lib
RCSwitch mySwitch = RCSwitch();
unsigned long lOldValue=0; // to check for consecutive reads on 433MHz
int motorPin = 5; // PWM-Pin to use for motor
void setup()
{
pinMode(motorPin, OUTPUT);
Serial.begin(9600);
// set-up rf receiver
mySwitch.enableReceive(0); // 433MHz Receiver on interrupt 0 => that is pin #2
}
void loop()
{
if (mySwitch.available())
{
int value = mySwitch.getReceivedValue();
// only react, if at least two times same value received
if (value == lOldValue)
{
if (value == 0)
{
Serial.print("Unknown encoding");
}
else
{
Serial.print("Received ");
Serial.print( mySwitch.getReceivedValue() );
Serial.print(" / ");
Serial.print( mySwitch.getReceivedBitlength() );
Serial.print("bit ");
Serial.print("Protocol: ");
Serial.println( mySwitch.getReceivedProtocol() );
// One of the keys on the remote
if (value == 274393) {
Serial.println("got start code, starting motor");
analogWrite(motorPin, 100); // start the motor
}
// another key on the remote
if (value == 270384) {
Serial.println("got stop code, stopping motor");
analogWrite(motorPin, 0); // stop the motor
}
}
}
lOldValue = value;
mySwitch.resetAvailable();
}
}
when i run the code and click on the remote, i get different values shown depending on the key i press. So the wireless receiver works as expected.
When i receive the right value for starting the motor, the motor really begins to turn, so this works as well.
And here the fun part starts:
As soon as i use the analogWrite function to send data to the PWM port the motor is connected to, the wireless receiver stops working (or at least I do not get any more values when pressing a key on the remote).
I found a few similar posts/problem descriptions on the net which said to try the following:
Use another pin for PWM (due to possible interrupt conflicts). I tried that as well, same behaviour
Use external power supply instead of USB-Cable, which helped somebody resolve this issue. Not here. Does not work either
So the question is:
Does anybody know how to combine those two things together so a can use the wireless receiver to get commands and switch on/off the motor with it?
I have the same problem in the past. The problem is the ability of arduino to supply them both. I recommend to use external power supply for the receiver or for the motor (it's best to do that for the motor but according to your circuit it's impossible) like the 545043YwRobot and supply the other from the arduino (I hope this is not what you try already, if so i'm sorry).
Hope it's help.
Yoav
Examples of writing to a port seem to always use the port number as a constant, eg,
OCR2A = 180;
How do you write to the port when the port is unknown until run time. For example,
int port = (buttonPressed) ? 0x3b : 0x3c;
portWrite( port, 180 );
What I cannot find is the funtion portWrite(). Does something like that exist?
Robert's answer has some imprecise assertions and an incomplete answer.
Writing directly to port registers you can ruin other settings of the port and sometimes cause permanent damage to controller.
Can ruin other settings: true, you have to know what you are doing (for instance what pins are on the port you are manipulating, and know what are the functions you want to keep.
Can cause permanent damage: not really, or better not because of the port manipulation. If you wire a short circuit to ground and then set it as an output to 1, you can damage it whether you are using the port register or the digitalwrite. You have to be careful in both ways.
Now, returning to your problem, the enumeration is one way, but since the PORTB, PORTC, PORTD are just short name for values, you can set a variable and then use it to indirectly access it.
The type for this kind of variable is a volatile pointer to a byte (volatile means that write and read operations cannot be optimized by the compiler, since the value can change even between two operations):
volatile uint8_t *variablePortRegister;
You just have to load it with the address (so with the & symbol) of the register you want to change:
variablePortRegister = &PORTC;
then use the pointer to change the value
PORTC = 0x12;
becomes
(*variablePortRegister) = 0x12;
This is a short example. For it to work, connect a LED with resistor on arduino pin 5 (bit 5 of PORTD). The LED on the board (labeled L) is connected to pin 13 (bit 5 of PORTB).
The sketch will make one of the two leds blink for five times, then switch to the other. Only port manipulation instructions are used, and you can find that the way to read the port is the same as the one to write it.
volatile uint8_t *myportreg;
unsigned long lastTime;
uint8_t counter;
void setup() {
DDRB |= 0x20;
DDRD |= 0x20;
PORTB = 0;
PORTD = 0;
counter = 99; // trigger the register change immediately
}
void loop() {
if (counter >= 10)
{
counter = 0;
if (myportreg == &PORTD)
myportreg = &PORTB;
else
myportreg = &PORTD;
}
if ((millis() - lastTime) > 500)
{
lastTime = millis();
// change bit 5 of register
*myportreg = 0x20 ^ (*myportreg);
counter++;
}
}
EDIT: as Robert pointed out, it's much better to "use" just the pins you need (in this case, bit 5 of port B and D) rather than setting the whole port; this way you minimize the risk of screwing up something else. This edit is already included in the above code, so the code is correct
The port is a bit in one particular register. If you know the register and the position of the port in that particular register you can try this:
register = (1<<port) || register
to set the port to 1 and
register = (1<<port)^-1 && register
to set the port to 0.
Of course, you will need a switch somewhere to determine the register and the bit of the port in the register given the port name.
I'll go right to the point. My arduino reads values from the adc port and send them via serial port(values from 0 to 255). I save them in a byte type vector. After sending an specific signal to arduino, it starts to send to Qt app the data saved in the vector. Everything is working except that the arduino should send 800 values and the app receives less values than that. If I set the serial baud rate to 9600, I get 220 values. If, instead, I set the baud rate to 115200, I get only 20 values. Can you guys help me to fix this? I would like to use 115200 baud rate, because I need a good trasmision speed at this project(Real time linear CCD). I'll leave some code below:
Arduino code:
void sendData(void)
{
int x;
for (x = 0; x < 800; ++x)
{
Serial.print(buffer[x]);
}
}
This is the function that sends the values. I think is enough information, so I summarized it. If you need more code, please let me know.
Qt serial port setting code:
...
// QDialog windows private variables and constants
QSerialPort serial;
QSerialPortInfo serialInfo;
QList<QSerialPortInfo> listaPuertos;
bool estadoPuerto;
bool dataAvailable;
const QSerialPort::BaudRate BAUDRATE = QSerialPort::Baud9600;
const QSerialPort::DataBits DATABITS = QSerialPort::Data8;
const QSerialPort::Parity PARITY = QSerialPort::NoParity;
const QSerialPort::StopBits STOPBITS = QSerialPort::OneStop;
const QSerialPort::FlowControl FLOWCONTROL = QSerialPort::NoFlowControl;
const int pixels = 800;
QVector<double> data;
unsigned int dataIndex;
QByteArray values;
double maximo;
...
// Signal and slot connection.
QObject::connect(&serial, SIGNAL(readyRead()), this,SLOT(fillDataBuffer()));
...
// Method called when there's data available to read at the serial port.
void Ventana::fillDataBuffer()
{
dataIndex++;
data.append(QString::fromStdString(serial.readAll().toStdString()).toDouble());
if(data.at(dataIndex-1) > maximo) maximo = data.at(dataIndex-1);
/* The following qDebug is the one I use to test the recieved values,
* where I check that values. */
qDebug() << data.at(dataIndex-1);
}
Thanks and sorry if it's not so clear, it has been an exhausting day :P
Ok... I see two probelms here:
Arduino side: you send your data in a decimal form (so x = 100 will be sent as 3 characters - 1, 0 and 0. You have no delimiter between your data, so how your receiver will know that it received value 100 not three values 1, 0 and 0? Please see my answer here for further explanation on how to send ADC data from Arduino.
QT side: There is no guarantee on the moment when readyRead() signal will be triggered. It may be immediately after first sample arrives, but it may be raised after there are already couple of samples inside the serial port buffer. If that happens, your method fillDataBuffer() may process string 12303402 instead of four separate strings 123, 0, 340 and 2, because between two buffer reads four samples arrived. The bigger the baudrate, the more samples will arrive between the reads, which is why you observe less values with a bigger baud rate.
Solution for both of your problems is to append some delimiting byte for your data, and split the string in the buffer on that delimiting byte. If you don't want to have maximum data throughput, you can just do
Serial.print(buffer[x]);
Serial.print('\n');
and then, split incoming string on \n character.
Thank you very much! I did what you said about my arduino program and after solving that, I was still not getting the entire amount of data. So the the problem was in Qt. How you perfectly explain, the serial buffer was accumulating the values too fast, so the slot function "fillDataBuffer()" was too slow to process the arriving data. I simplified that function:
void Ventana::fillDataBuffer()
{
dataIndex++;
buffer.append(serial.readAll());
}
After saving all the values in the QByteArray buffer, I process the data separately.
Thanks again man. Your answer was really helpful.
i'd like to put the SAM3X chip on sleepmode until a character arrives on the serial port. i was thinking of using an ausiliary flag in the Serial interrupt procedure in order to trigger the wake up procedure? what do you think abou? any advice or any other way i should follow or try?
I recommend reviewing .\arduino-1.5.2\hardware\arduino\sam\cores\arduino\UARTClass.cpp as its UARTClass::begin will detail how the Arduino Framework initializes the SAM's Serial IRQ with:
// Configure interrupts
_pUart->UART_IDR = 0xFFFFFFFF;
_pUart->UART_IER = UART_IER_RXRDY | UART_IER_OVRE | UART_IER_FRAME;
// Enable UART interrupt in NVIC
NVIC_EnableIRQ(_dwIrq);
// Enable receiver and transmitter
_pUart->UART_CR = UART_CR_RXEN | UART_CR_TXEN ;
Where you will need to ensure the baud rate generator is not stopped while in sleepmode.
Along with reading the SAM3X data sheet starting with 5.5.3. which leaves the peripheral clocks enabled.
looks like you may be able to insert the wake up into the UARTClass::IrqHandler
void UARTClass::IrqHandler( void )
{
uint32_t status = _pUart->UART_SR;
// Did we receive data ?
if ((status & UART_SR_RXRDY) == UART_SR_RXRDY)
{
// wake up!!!! Not sure if you even need to wakeup, it should from the sleepmode
_rx_buffer->store_char(_pUart->UART_RHR);
}
With regards to sleeping:
\arduino-1.5.2\hardware\arduino\sam\system\libsam\source\pmc.c
Line 972: void pmc_enable_sleepmode(uint8_t uc_type)
Line 988: void pmc_enable_waitmode(void)
Line 1009: void pmc_enable_backupmode(void)
So I would suspect the following:
pmc_enable_sleepmode(WFI);
would put the unit a sleep and the IrqHandler of the UART_SR_RXRDY would wake itself up, without any code change.
One other alternative would be to use the serial pin's IO as to trigger an interrupt.
attachInterrupt(0, EnableSerialRX, CHANGE);
It would though, loose at least the first byte. the trade off is that you can use the lower power modem of pmc_enable_backupmode() rather than sleep