Hello guys,
I have a device (smoke alarm) that sends a stream of bits over a wire (1 GND + 1 Data) when an event happens (smoke is detected, the TEST button is pressed, low battery....). The bits are transmitted in the format (4 start bits)+(8 data bits) like: 1010 11000111 at a transmission rate of 1000 bits per second.
My question is: How can I detect and process the bits in Arduino?
I've tried to detect it with only if (digitalRead(pin) == HIGH){ and it works but it obviously just detects just a 1 rather than the entire stream.
1. Your smoke detector is connected with this MCU: HT45F23A MCU. 2. The HT45F23A MCU has two communication protocols: SPI Port and I2C Bus. 3. To communicate with Arduino (UNO), one has to use either the SPI Port or the I2C Bus. 4. I have difficulties to understand from which pin (1-Wire) of the HT45F23A MCU you are getting the 12-bit stream what you have said in your original post.
GolamMostafa:
If I have understood to some extent:
1. Your smoke detector is connected with this MCU: HT45F23A MCU. 2. The HT45F23A MCU has two communication protocols: SPI Port and I2C Bus. 3. To communicate with Arduino (UNO), one has to use either the SPI Port or the I2C Bus. 4. I have difficulties to understand from which pin (1-Wire) of the HT45F23A MCU you are getting the 12-bit stream what you have said in your original post.
No, you've misunderstood.
The Smoke detector is: a HT45F23A chip with a buzzer, battery and smoke sensor. It has 2 wires to send data to other devices (IT IS NOT I2C or SPI). It's a custom made protocol that transmits 12 bits of data at 1kbps baud rate through 1 wire. The 2nd wire is just ground(GND).
I want to detect those 12 bits of data in my Arduino UNO. How to do that?
Robin2:
What happens before and after the device sends a message?
...R
Before, Arduino is just waiting in the void loop() function for the pin to read the stream. After, Arduino just lights up an LED once the stream is detected, or even better, display it on the Serial.println(pin)
alexceltare2:
I want to detect those 12 bits of data in my Arduino UNO. How to do that?
According to the information you give, it's a one-way data flow, and you need to implement the reception routine since your description of the protocol doesn't match the UART ("serial") one.
It's not 1-Wire either, because it doesn't have that much overhead.
Knowing the protocol is the first step, however you also have to be sure about these three things:
Will the start bits always have the same pattern? If not, then they probably are part of the data section, or maybe parity/sort of a checksum, or maybe special flags to treat the frame ("packet") differenly.
This one might be tough to answer: bit order. You'll have to be sure what's the first data bit to shift in: least significant (LSB) or most significant (MSB). In serial communications like SPI, the MSB goes first most of the times; but there's always the chance it's the other way around.
Active state: if the first start bit is 1, then it has to be active high; if the first is 0, then it has to be active low. This is important in order to define which type of edge (state transition) begins the frame (aka first start bit).
After being sure of all this, lemme tell you that will need to spend a timer and a pin-triggered interrupt (pin change or external); and probably a circular (ring) buffer in case the program isn't able to receive on time the incoming data. It's better to handle all this via interrupts, because manually initiating the capture process can lead to mistiming and a corrupted byte as result.
alexceltare2:
Before, Arduino is just waiting in the void loop() function for the pin to read the stream. After, Arduino just lights up an LED once the stream is detected, or even better, display it on the Serial.println(pin)
Sorry. I guess I was not clear enough.
I want to know what is the state of the signal going to the Arduino prior to and subsequent to a message.
Will the start bits always have the same pattern? If not, then they probably are part of the data section, or maybe parity/sort of a checksum, or maybe special flags to treat the frame ("packet") differenly.
This one might be tough to answer: bit order. You'll have to be sure what's the first data bit to shift in: least significant (LSB) or most significant (MSB). In serial communications like SPI, the MSB goes first most of the times; but there's always the chance it's the other way around.
Active state: if the first start bit is 1, then it has to be active high; if the first is 0, then it has to be active low. This is important in order to define which type of edge (state transition) begins the frame (aka first start bit).
Yes, the start bits are always 1010.
Like I said, is not SPI. The bits transmitted are in the order i typed:1010 11001100 whereas 1010 are the start bits only, so yeah, it does transmit from MSB to LSB.
Yes, is active high, meaning the data pin is always 0 before transmission.
I would attempt this by starting from the SoftwareSerial library. That detects a Serial start bit and samples the input at the right time to extract the data.
It should not be too hard to modify the bit counter to reset after the first 4 bits are checked.
Robin2:
I think you have answered it in item 3 in Reply #9. From that I assume that the signal is always HIGH unless data is being sent.
However, if the system idles HIGH the first bit must surely be a 0?
I guess at the back of my mind I wonder if there are two 8-bit bytes being sent but you are only conscious of the last 4 bits of the first byte?
...R
Actually, the DATA pin is always LOW/0/ActiveHigh, thus the start bits 1010. So i need a snippet to detect the start bits and the next 8 bits packet. The biggest problem that I've got is the data synchronisation since there is no common Clock/CLK, but i do know the bits are transmitted at 1kbit/s
MorganS:
I would attempt this by starting from the SoftwareSerial library. That detects a Serial start bit and samples the input at the right time to extract the data.
It should not be too hard to modify the bit counter to reset after the first 4 bits are checked.
But since it expects UART packets (or frames), it will also expect the stop bits, which are absent on this unknown serial protocol (according to the provided description).
alexceltare2:
So i need a snippet to detect the start bits and the next 8 bits packet. The biggest problem that I've got is the data synchronisation since there is no common Clock/CLK, but i do know the bits are transmitted at 1kbit/s
Even creating a snippet of this may take a while, but is possible.
To make the process easier to understand, you have to divide it into steps:
Decide the data input pin; depending on the option you'll have to use either an external interrupt (only pins 2 and 3 if using ATmega328P), or a pin change interrupt (any GPIO except A6 and A7 in case of a Nano/Pro Mini). This kind of interrupt will be used to trigger the capture process, by detecting the start bits without active polling.
After detecting two rising edges (due to the constant pattern) with the previous interrupt, disable this one and enable the timer and its interrupt; resetting its value to zero as well (one bit must be skipped since at that moment the fourth start bit passes by, and of course it isn't part of the data). After confirming a packet by receiving the start bits, this detection is disabled because it's no longer necessary; from here a timed interrupt kicks in to... you guessed: sample the data bits at a precise intervals of 1 millisecond (1 Kbps as you expect).
When the timed interrupts takes place, it samples (reads) the data pin state for 8 milliseconds (8 times); every trigger will increment a counter, read the pin's state, and shift the bit into an intermediate byte variable.
After the 8 bits (8 milliseconds elapsed since the timer kicked in), which you can notice when the counter reaches a value of 8, place the intermediate variable's value into a circular buffer (or hope the main program can retrieve it before it gets overwritten by another incoming packet), reset the counter, zero up the intermediate variable, stop the timer, disable this interrupt and reenable the other one.
If you could follow my idea, all these steps should repeat automatically and correctly every time a packet comes in.
I recommend you to do this via interrupts; because if you do all this in the main program, you could have missed the start bits even before getting started.
PD: in fact, SoftwareSerial is possible thanks to interrupts; you don't even have to worry about sampling the data at the moment it comes in.
The problem is that you can't use this for your project, unless you do the required modifications (4 start bits instead of 2, no stop bits instead of 1). It's almost like UART at 1000 bps, but the packet format differs in the amount of start and stop bits.
alexceltare2:
Actually, the DATA pin is always LOW/0/ActiveHigh, thus the start bits 1010. So i need a snippet to detect the start bits and the next 8 bits packet. The biggest problem that I've got is the data synchronisation since there is no common Clock/CLK, but i do know the bits are transmitted at 1kbit/s
Sorry, I did get my HIGHs and LOWs mixed up.
Have you studied the code in my link? It uses the exact same principles as the SoftwareSerial library but I think it will be more accessible than the code in the library,
If you know the bit rate then you just need to sample the data at the centre point of each bit. The transition from the IDLE LOW to the first HIGH gives you the start point for the timing. Note that the time from the transition to the middle of the bit following the start bit will be 1.5 bit periods. There will be no need to sample the middle of the start bit.
I have made a setup using UNO (Sender) and NANO (Receiver) in which the UNO sends the frame 1010 11000111 and the NANO receives the frame correctly. The bit period of 1 ms has been generated using Timer-1 of the MCU. The UNO sends the test frame at 5-sec interval. Check that the codes could be useful for you.
I think the code in Reply #16 will only work if there is no "interference". For example, what should happen if the opening data is 11010 or 1001010? Both of those have a valid sequence of 1010 although I can see an argument for rejecting the first one because the initial 1 (of the valid sequence) does not follow a LOW. However the second one seems to be perfectly valid.
@alexceltare2, please post a link to the document that defines the protocol you are trying to work with?
I would like to believe that there is a fixed gap (pause) between the transmissions of the frames. This gap will help the receiver not to catch 1010 of the data byte as the sync pattern. The receiver will be looking for the gap; if the gap is found longer that 1ms (1-bit period) (say, 1.5 ms), it is almost sure that next bit is the 1st bit of the 4-bit sync pattern.
GolamMostafa:
I would like to believe that there is a fixed gap (pause) between the transmissions of the frames.
You have raised another complication I had not thought of - the sync pattern appearing in the data byte. I was just thinking of the possibility of confusion surrounding the sync pattern.
If the system starts "listening" while a data byte is being sent and if the data byte includes the sync pattern how will it know that it is not really the sync pattern?
Until the OP provides the detailed specifications we cannot know.