I'd use an Arduino board that has multiple hardware UARTs available. Say a Mega or a Teensy 3.2.
david_2018:
With the OP's delay of 15mS between bits, that would be 66.67 baud. Assuming the data rate cannot reliably be increased much above that, you would need a software serial library that could handle very low baud rates.
Have you looked at how software serial works?
The start bit triggers an interrupt and the ISR does not return until the entire byte is read.
The code does software delays inside the ISR for the bit times.
Depending on what is else going on or needs to go on, it can cause issues and the lower the baud rate the more likely it will cause issues.
Software serial kind of depends on using a baud rate in a "Goldilocks" range.
i.e Not too fast that it can't keep up, and not too slow that the s/w delays cause issues.
--- bill
So I am definitely confused now haha
I tried playing around with this library
![]()
GitHub - HobbyTransform/Encoded-Laser-and-LED-Serial-Communication which seemed to be clocking at the 16mHz rate and anytime the message sent was longer than like "hello" it appeared to get off. I am wondering if this is what Bill means with the goldilocks range. As to Bill's earlier comment about having an ISR account for the the time entered and whether the input is high or low, does this look like what you mean?
if(cur > 0){ //cur is millis() set in ISR, you can use it to tell how long you have been in the ISR
if(charCount == 0){ //start of char
howManyCharsCame = ((millis()-cur)-(PERIOD*1.5))/PERIOD; //account for start of message extra time
}
else{
howManyCharsCame = ((millis()-cur)/PERIOD;
}
for(int i = charCount; i < howManyCharsCame; i++){
recArray[ i ] = rec;
i++;
cur = 0;
}
charCount += howManyCharsCame;
if(charCount >= 7){
charCount = 0;
cur = 0;
}
}
ISR(ANALOG_COMP_vect)
{
cur = millis();
rec = digitalRead(6);
}
skrinsky,
The code you showed is doing part in the ISR and part in the foreground.
But the code doesn't appear to be doing any actual type of decoding.
In that code, the ISR saves the time when the interrupt occurred, along with a single data sample and the foreground uses it later.
That type of strategy can work as long as your foreground code can always poll fast enough to check on things to process the data samples.
Otherwise, you would need to move more of the realtime decoding into the ISR or at least provide some sort of buffer for the data samples.
What I mentioned previously wasn't just marking when the ISR occurred and saving a data sample for the foreground to deal with.
It was about doing realtime decoding by using the timing of when interrupts occured due to pin status changes and doing the decoding in the ISR, and then having the ISR set a flag to tell the foreground that the decoding was completed so it could grab the decoded data.
It requires more state tracking in the ISR and doing the decoding right there based on the state and the timing of the pin changes.
A 3rd alternative is to take constant interrupts at a fixed interval to poll the state of the pin in the ISR and do the decoding that way.
All 3 methods can work, but they are very different in how they work and are implemented.
--- bill
Just to make your project that little bit more complicated - and reliable...
Ideally you should send a carrier between the tax and rx nodes..
you modulate that with your data.
The advantage is that arbitrary flashes of ambient light, or a bird flying through the beam will be detected.
The method is quite simple in software, but It’s too complex to explain here, try google for ‘modulated carrier light beam’, that might help you. You can also add error detection and correction if you want to go that far.
Is there some reason you need to use lasers instead of radio or wifi?
this project involves encryption so radio or wifi could be intercepted while light in a device is safest. Here is some messy code of an ISR that works...though things seem to be able to get off if I type SUPER fast but not if i type semi-fast...not incredibly ideal and I'm about to check out the modulated carrier light suggestion
ISR(ANALOG_COMP_vect)
{
cur = millis(); //time at entering ISR
if(charCount == -1 || charCount == -2){ //first change pre-message start
save = digitalRead(7); //first bit read
charCount++;
}
else{
int blah = (cur-prev); //this is the amount of time we spent on the last bit, so how many 1's or 0's in a row
while(blah > 1){
if(charCount == 0 && beenHere == false){
blah-=PERIOD; //first change is just telling that byte is about to be sent
beenHere = true;
}
if(blah > 1){
blah -= PERIOD;
rec[ charCount ] = int(save);
charCount++;
if(charCount == 7){
ding = 0;
for(int i = 0; i < 8; i++){
bool setter = rec[ i ];
ding = ding | setter << i;
}
if(save == 0){
charCount = -1; //binary ends in 0
}
else{
charCount = -2; //binary ends in 1
}
beenHere = false;
blah = 0;
charReceived = true;
}
}
}
save = !save; //flip upon change
}
prev = cur;
}
Why have you abandoned the concept of using hardware UART? That handles all the timing in hardware and does the UART <--> Buffer transfer via interrupts. All you have to do is print() (or write()) the ASCII characters on the TX side and read() them on the RX side when they're available().
I got an op amp and got it to work as an external comparator with the mega, but couldn't figure out from there how to use UART to do any timing...got lost and overwhelmed to be honest and went back to the original that was semi working. If you can point me in a direction to understand how to use UART to do the timing stuff that would be amazing. I did this
void setup() {
pinMode(19, INPUT_PULLUP);
Serial.begin(9600);
Serial1.begin(9600);
}
void loop() {
// Check for received Characters from the computer
if (Serial1.available())
{
// Write what is received to the serial1 port
Serial.println(Serial1.read());
}
}
in which case it prints when there has been a change...but I don't know how to turn that into a readable char without having a square wave period? do you know what I mean?
Please do a better job of describing your hardware connections when attempting to use a UART. Both TX and RX, include schematics. Then post your complete code, both TX and RX. Post your code using Code Tags. If you don't know what those are, see the very cleverly-titled post at the top of each forum page: Read this before posting a programming question ...
Pay particular attention to Item #6.
skrinsky:
in which case it prints when there has been a change...but I don't know how to turn that into a readable char without having a square wave period? do you know what I mean?
The bit rate (bits per second) is that number you pass to Serial1.begin(). Try setting that to 67 instead of 9600 to closely match your 15 millisecond bit width (66.67 bits per second). Then when you send a start bit (HIGH), 8 data bits, and a stop bit (LOW) the 8 data bits should arrive from Serial1.read().
You should probably use Serial1.write() on the sending end. Just make sure the bit rate is the same at both ends. You may even be able to increase the data rate considerably. Common slow speeds are 110, 300, or 1200 bits per second.
This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.