Bluetooth Low Energy (BLE) beacon with nRF24L01(+). Data is received and displayed by Android device (Android app source code is attached).
nRF24L01 as Bluetooth Low Energy (BLE) Broadcaster/Beacon
Temperature measured by a DS1820 sensor is broadcasted by a nRF24L01(+) module as Bluetooth Low Energy signal. Data is then received and displayed on an Android device (smartphone/tablet) with Bluetooth Low Energy (Bluetooth Smart) enabled. In order to have Bluetooth LE available your device should run Android 4.3 or more recent.
Needed parts:
- mbed module
- nRF24L01 or nRF24L01+ module
- DS18B20 or DS18S20 sensor
- 4.7k Ohm resistor
- Wires
- Breadboard
- Android device with Bluetooth LE enabled (Android 4.3 or more recent)
Zoom in
Figure 1: The hookup and the Android app in action
It was Dmitry Grinberg who figured out how to use nRF24L01 for BLE.
Read his amazing "Bit-banging" Bluetooth Low Energy.
Thank you Dmitry!
I ported the code to mbed from Lijun's repository.
Read his very neat article on the topic.
Thank you Lijun!
It takes just few steps to build a Temperature Beacon
- Connect the nRF24L01(+) module and the DS1820 sensor to the mbed board according to the pin assignment defined in main.cpp. Don't forget to connect a 4.7k Ohm resistor between the DS1820's data pin and the +3.3V pin.
Figure 2: nRF24L01(+) pinout
- Compile the project and save the binary file to your mbed module.
- Enable Bluetooth on the Android device.
- To view the raw data, install Nordic's nRF Master Control Panel (available at Google Play for free) to your Android device. Run the app and wait until a new nRF24L01 device is found. Do not tap the CONNECT button. This device is a broadcaster and enables only one way data flow (from the mbed to the Android). To see more details, tap the found nRF24L01 device on the left side of the screen and then the small RAW button which appears on the right side just below the CONNECT button. Now you should be able to see and check the raw bytes received from the mbed.
- Install the Android app:
- Download the TemperatureBeacon app to your computer's folder of choice.
- Open the folder and copy (send via Bluetooth or USB cable) the downloaded file to your Android device.
- To install the app, open the folder on the Android with the file downloaded in the previous step and tap it. - Once the app is installed and running:
- After a while you should see the temperature displayed on Android (See in Figure 1).
- Data is periodically updated. To verify that, touch the DS1820 sensor and you should see some new values.
If you'd like to adapt the Android app to your taste
- Install Android Studio onto your computer (Window, Mac, Linux). It's a fantastic IDE from Google for free.
- Download the Android app project to your computer's folder of choice and unzip.
- Start Android Studio, open the project downloaded in the previous step and have fun.
I have learnt a lot about Android and Bluetooth Low Energy here:
https://developer.android.com/guide/topics/connectivity/bluetooth-le.html,
https://thenewcircle.com/s/post/1553/bluetooth_smart_le_android_tutorial
The Android app is based on:
https://github.com/devunwired/accessory-samples/tree/master/BluetoothGatt.
Thank you Dave!
main.cpp@6:14d70104b0fc, 2015-12-15 (annotated)
- Committer:
- hudakz
- Date:
- Tue Dec 15 19:34:51 2015 +0000
- Revision:
- 6:14d70104b0fc
- Parent:
- 5:448e87318747
- Child:
- 7:79c3ff270db1
More mbed platforms included.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
hudakz | 0:6f3139e3410e | 1 | /* |
hudakz | 3:96153a5d95f6 | 2 | Using nRF24L01(+) as a Bluetooth Low Energy Advertiser/Broadcaster/Beacon |
hudakz | 3:96153a5d95f6 | 3 | by hacking an nRF24L01(+) module (which is under $1 per unit on eBay). |
hudakz | 0:6f3139e3410e | 4 | |
hudakz | 6:14d70104b0fc | 5 | See wiki page: <https://developer.mbed.org/users/hudakz/code/BLE_nRF24L01> |
hudakz | 6:14d70104b0fc | 6 | |
hudakz | 3:96153a5d95f6 | 7 | Note: It works with both nRF24L01 and nRF24L01+ modules. |
hudakz | 0:6f3139e3410e | 8 | |
hudakz | 6:14d70104b0fc | 9 | Temperature readings measured by a DS1820 chip are broacasted over Bluetooth LE. |
hudakz | 0:6f3139e3410e | 10 | (You can easily modify the code to broadcast some other custom data. |
hudakz | 0:6f3139e3410e | 11 | Only make sure not to exceed the 32 bytes packet length.) |
hudakz | 2:4f285d1d5c1f | 12 | |
hudakz | 2:4f285d1d5c1f | 13 | The data can be received and displayed on an Android device (smartphone/tablet) |
hudakz | 2:4f285d1d5c1f | 14 | with Bluetooth Low Energy (Bluetooth Smart) enabled. |
hudakz | 2:4f285d1d5c1f | 15 | In order to have Bluetooth 4.0 available (which implements Bluetooth LE) |
hudakz | 2:4f285d1d5c1f | 16 | your device should run Android 4.3 or more recent. |
hudakz | 0:6f3139e3410e | 17 | */ |
hudakz | 0:6f3139e3410e | 18 | |
hudakz | 0:6f3139e3410e | 19 | |
hudakz | 0:6f3139e3410e | 20 | #include "mbed.h" |
hudakz | 0:6f3139e3410e | 21 | #include "DS1820.h" |
hudakz | 0:6f3139e3410e | 22 | |
hudakz | 2:4f285d1d5c1f | 23 | #define DEBUG 1 |
hudakz | 2:4f285d1d5c1f | 24 | |
hudakz | 2:4f285d1d5c1f | 25 | #if DEBUG |
hudakz | 0:6f3139e3410e | 26 | Serial serial(USBTX, USBRX); |
hudakz | 2:4f285d1d5c1f | 27 | #endif |
hudakz | 0:6f3139e3410e | 28 | |
hudakz | 0:6f3139e3410e | 29 | // The MAC address of BLE advertizer -- just make one up |
hudakz | 6:14d70104b0fc | 30 | // If you decide to ceate more Beacons make sure that MAC address (MY_MAC) is unique for each beacon |
hudakz | 0:6f3139e3410e | 31 | |
hudakz | 0:6f3139e3410e | 32 | #define MY_MAC_0 0x11 |
hudakz | 0:6f3139e3410e | 33 | #define MY_MAC_1 0x12 |
hudakz | 0:6f3139e3410e | 34 | #define MY_MAC_2 0x33 |
hudakz | 0:6f3139e3410e | 35 | #define MY_MAC_3 0x44 |
hudakz | 0:6f3139e3410e | 36 | #define MY_MAC_4 0x55 |
hudakz | 0:6f3139e3410e | 37 | #define MY_MAC_5 0x66 |
hudakz | 0:6f3139e3410e | 38 | |
hudakz | 0:6f3139e3410e | 39 | #if defined(TARGET_LPC1768) |
hudakz | 0:6f3139e3410e | 40 | SPI spi(p11, p12, p13); // MOSI, MISO, SCK |
hudakz | 0:6f3139e3410e | 41 | DigitalOut cs(p8); // CSN (select SPI chip/slave) |
hudakz | 4:b3c5c54cfd21 | 42 | DigitalOut ce(p14); // CE (enable nRF24L01 chip) |
hudakz | 4:b3c5c54cfd21 | 43 | DS1820 ds1820(p15); // create a ds1820 sensor |
hudakz | 6:14d70104b0fc | 44 | #elif defined(TARGET_NUCLEO_F103RB) || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_F030R8) \ |
hudakz | 6:14d70104b0fc | 45 | || defined(TARGET_NUCLEO_F401RE) || defined(TARGET_NUCLEO_F302R8) || defined(TARGET_NUCLEO_L053R8) \ |
hudakz | 6:14d70104b0fc | 46 | || defined(TARGET_NUCLEO_F411RE) || defined(TARGET_NUCLEO_F334R8) || defined(TARGET_NUCLEO_F072RB) \ |
hudakz | 6:14d70104b0fc | 47 | || defined(TARGET_NUCLEO_F091RC) || defined(TARGET_NUCLEO_F303RE) || defined(TARGET_NUCLEO_F070RB) \ |
hudakz | 6:14d70104b0fc | 48 | || defined(TARGET_KL25Z ) || defined(TARGET_KL46Z) || defined(TARGET_K64F) || defined(TARGET_KL05Z) \ |
hudakz | 6:14d70104b0fc | 49 | || defined(TARGET_K20D50M) || defined(TARGET_K22F) \ |
hudakz | 6:14d70104b0fc | 50 | || defined(TARGET_NRF51822) \ |
hudakz | 6:14d70104b0fc | 51 | || defined(TARGET_RZ_A1H) |
hudakz | 6:14d70104b0fc | 52 | SPI spi(D11, D12, D13); // MOSI, MISO, SCK |
hudakz | 6:14d70104b0fc | 53 | DigitalOut cs(D6); // CSN (select SPI chip/slave) |
hudakz | 6:14d70104b0fc | 54 | DigitalOut ce(D7); // CE (enable nRF24L01 chip) |
hudakz | 6:14d70104b0fc | 55 | DS1820 ds1820(D8); // create a ds1820 sensor |
hudakz | 0:6f3139e3410e | 56 | |
hudakz | 0:6f3139e3410e | 57 | // If your board/plaform is not present yet then uncomment |
hudakz | 4:b3c5c54cfd21 | 58 | // the following five lines and replace TARGET_YOUR_BOARD, SPI_MOSI, SPI_MISO, SPI_SCK, SPIS_CS, CE_PIN and DS1820_DATA_PIN as appropriate. |
hudakz | 0:6f3139e3410e | 59 | |
hudakz | 0:6f3139e3410e | 60 | //#elif defined(TARGET_YOUR_BOARD) |
hudakz | 0:6f3139e3410e | 61 | //SPI spi(SPI_MOSI, SPI_MISO, SPI_SCK); |
hudakz | 0:6f3139e3410e | 62 | //DigitalOut cs(SPI_CS); // CSN (select SPI chip/slave) |
hudakz | 0:6f3139e3410e | 63 | //DigitalOut cs(CE_PIN); // CE (enable nRF24L01+ chip) |
hudakz | 4:b3c5c54cfd21 | 64 | //DS1820 ds1820(DS1820_DATA_PIN);// create a ds1820 sensor |
hudakz | 0:6f3139e3410e | 65 | |
hudakz | 0:6f3139e3410e | 66 | #endif |
hudakz | 0:6f3139e3410e | 67 | |
hudakz | 0:6f3139e3410e | 68 | uint8_t buf[32]; |
hudakz | 0:6f3139e3410e | 69 | |
hudakz | 0:6f3139e3410e | 70 | /** |
hudakz | 4:b3c5c54cfd21 | 71 | * @brief Implements CRC with LFSR |
hudakz | 0:6f3139e3410e | 72 | * @note |
hudakz | 4:b3c5c54cfd21 | 73 | * @param data: packet data |
hudakz | 4:b3c5c54cfd21 | 74 | * len: packet length |
hudakz | 4:b3c5c54cfd21 | 75 | * dst: destination/location of CRC |
hudakz | 0:6f3139e3410e | 76 | * @retval |
hudakz | 0:6f3139e3410e | 77 | */ |
hudakz | 0:6f3139e3410e | 78 | void bleCRC(const uint8_t* data, uint8_t len, uint8_t* dst) { |
hudakz | 0:6f3139e3410e | 79 | uint8_t v, t, d; |
hudakz | 0:6f3139e3410e | 80 | |
hudakz | 0:6f3139e3410e | 81 | while(len--) { |
hudakz | 0:6f3139e3410e | 82 | d = *data++; |
hudakz | 0:6f3139e3410e | 83 | for(v = 0; v < 8; v++, d >>= 1) { |
hudakz | 0:6f3139e3410e | 84 | t = dst[0] >> 7; |
hudakz | 0:6f3139e3410e | 85 | dst[0] <<= 1; |
hudakz | 0:6f3139e3410e | 86 | if(dst[1] & 0x80) |
hudakz | 0:6f3139e3410e | 87 | dst[0] |= 1; |
hudakz | 0:6f3139e3410e | 88 | dst[1] <<= 1; |
hudakz | 0:6f3139e3410e | 89 | if(dst[2] & 0x80) |
hudakz | 0:6f3139e3410e | 90 | dst[1] |= 1; |
hudakz | 0:6f3139e3410e | 91 | dst[2] <<= 1; |
hudakz | 0:6f3139e3410e | 92 | |
hudakz | 0:6f3139e3410e | 93 | if(t != (d & 1)) { |
hudakz | 0:6f3139e3410e | 94 | dst[2] ^= 0x5B; |
hudakz | 0:6f3139e3410e | 95 | dst[1] ^= 0x06; |
hudakz | 0:6f3139e3410e | 96 | } |
hudakz | 0:6f3139e3410e | 97 | } |
hudakz | 0:6f3139e3410e | 98 | } |
hudakz | 0:6f3139e3410e | 99 | } |
hudakz | 0:6f3139e3410e | 100 | |
hudakz | 0:6f3139e3410e | 101 | /** |
hudakz | 4:b3c5c54cfd21 | 102 | * @brief Reverses bit order in a single byte |
hudakz | 0:6f3139e3410e | 103 | * @note |
hudakz | 4:b3c5c54cfd21 | 104 | * @param a: byte to be reveresed |
hudakz | 4:b3c5c54cfd21 | 105 | * @retval byte with reveresed bit order |
hudakz | 0:6f3139e3410e | 106 | */ |
hudakz | 0:6f3139e3410e | 107 | uint8_t swapBits(uint8_t a) { |
hudakz | 0:6f3139e3410e | 108 | uint8_t v = 0; |
hudakz | 0:6f3139e3410e | 109 | if(a & 0x80) |
hudakz | 0:6f3139e3410e | 110 | v |= 0x01; |
hudakz | 0:6f3139e3410e | 111 | if(a & 0x40) |
hudakz | 0:6f3139e3410e | 112 | v |= 0x02; |
hudakz | 0:6f3139e3410e | 113 | if(a & 0x20) |
hudakz | 0:6f3139e3410e | 114 | v |= 0x04; |
hudakz | 0:6f3139e3410e | 115 | if(a & 0x10) |
hudakz | 0:6f3139e3410e | 116 | v |= 0x08; |
hudakz | 0:6f3139e3410e | 117 | if(a & 0x08) |
hudakz | 0:6f3139e3410e | 118 | v |= 0x10; |
hudakz | 0:6f3139e3410e | 119 | if(a & 0x04) |
hudakz | 0:6f3139e3410e | 120 | v |= 0x20; |
hudakz | 0:6f3139e3410e | 121 | if(a & 0x02) |
hudakz | 0:6f3139e3410e | 122 | v |= 0x40; |
hudakz | 0:6f3139e3410e | 123 | if(a & 0x01) |
hudakz | 0:6f3139e3410e | 124 | v |= 0x80; |
hudakz | 0:6f3139e3410e | 125 | return v; |
hudakz | 0:6f3139e3410e | 126 | } |
hudakz | 0:6f3139e3410e | 127 | |
hudakz | 0:6f3139e3410e | 128 | /** |
hudakz | 4:b3c5c54cfd21 | 129 | * @brief Implements whitening with LFSR |
hudakz | 0:6f3139e3410e | 130 | * @note |
hudakz | 4:b3c5c54cfd21 | 131 | * @param data: location of the data to be whiten |
hudakz | 4:b3c5c54cfd21 | 132 | * len: data length |
hudakz | 4:b3c5c54cfd21 | 133 | * whitenCoeff: whitening coefficient |
hudakz | 0:6f3139e3410e | 134 | * @retval |
hudakz | 0:6f3139e3410e | 135 | */ |
hudakz | 0:6f3139e3410e | 136 | void bleWhiten(uint8_t* data, uint8_t len, uint8_t whitenCoeff) { |
hudakz | 0:6f3139e3410e | 137 | uint8_t m; |
hudakz | 0:6f3139e3410e | 138 | while(len--) { |
hudakz | 0:6f3139e3410e | 139 | for(m = 1; m; m <<= 1) { |
hudakz | 0:6f3139e3410e | 140 | if(whitenCoeff & 0x80) { |
hudakz | 0:6f3139e3410e | 141 | whitenCoeff ^= 0x11; |
hudakz | 0:6f3139e3410e | 142 | (*data) ^= m; |
hudakz | 0:6f3139e3410e | 143 | } |
hudakz | 0:6f3139e3410e | 144 | |
hudakz | 0:6f3139e3410e | 145 | whitenCoeff <<= 1; |
hudakz | 0:6f3139e3410e | 146 | } |
hudakz | 0:6f3139e3410e | 147 | |
hudakz | 0:6f3139e3410e | 148 | data++; |
hudakz | 0:6f3139e3410e | 149 | } |
hudakz | 0:6f3139e3410e | 150 | } |
hudakz | 0:6f3139e3410e | 151 | |
hudakz | 0:6f3139e3410e | 152 | /** |
hudakz | 4:b3c5c54cfd21 | 153 | * @brief Starts whitening |
hudakz | 4:b3c5c54cfd21 | 154 | * @note the value we actually use is what BT'd use left shifted one...makes our life easier |
hudakz | 4:b3c5c54cfd21 | 155 | * @param chan: BT channel |
hudakz | 4:b3c5c54cfd21 | 156 | * @retval single byte |
hudakz | 0:6f3139e3410e | 157 | */ |
hudakz | 0:6f3139e3410e | 158 | static inline uint8_t bleWhitenStart(uint8_t chan) { |
hudakz | 0:6f3139e3410e | 159 | return swapBits(chan) | 2; |
hudakz | 0:6f3139e3410e | 160 | } |
hudakz | 0:6f3139e3410e | 161 | |
hudakz | 0:6f3139e3410e | 162 | /** |
hudakz | 4:b3c5c54cfd21 | 163 | * @brief Assembles the packet to be transmitted |
hudakz | 0:6f3139e3410e | 164 | * @note |
hudakz | 4:b3c5c54cfd21 | 165 | * @param data: packet data |
hudakz | 4:b3c5c54cfd21 | 166 | * len: packet length |
hudakz | 4:b3c5c54cfd21 | 167 | * dst: BLE channel |
hudakz | 0:6f3139e3410e | 168 | * @retval |
hudakz | 0:6f3139e3410e | 169 | */ |
hudakz | 0:6f3139e3410e | 170 | void blePacketEncode(uint8_t* packet, uint8_t len, uint8_t chan) { |
hudakz | 0:6f3139e3410e | 171 | // Length is of packet, including crc. pre-populate crc in packet with initial crc value! |
hudakz | 0:6f3139e3410e | 172 | uint8_t i, dataLen = len - 3; |
hudakz | 0:6f3139e3410e | 173 | bleCRC(packet, dataLen, packet + dataLen); |
hudakz | 0:6f3139e3410e | 174 | for(i = 0; i < 3; i++, dataLen++) |
hudakz | 0:6f3139e3410e | 175 | packet[dataLen] = swapBits(packet[dataLen]); |
hudakz | 0:6f3139e3410e | 176 | bleWhiten(packet, len, bleWhitenStart(chan)); |
hudakz | 0:6f3139e3410e | 177 | for(i = 0; i < len; i++) |
hudakz | 0:6f3139e3410e | 178 | packet[i] = swapBits(packet[i]); // the byte order of the packet should be reversed as well |
hudakz | 0:6f3139e3410e | 179 | } |
hudakz | 0:6f3139e3410e | 180 | |
hudakz | 0:6f3139e3410e | 181 | /** |
hudakz | 4:b3c5c54cfd21 | 182 | * @brief Sends cmommand to nRF24L01 |
hudakz | 0:6f3139e3410e | 183 | * @note |
hudakz | 4:b3c5c54cfd21 | 184 | * @param cmd: Command |
hudakz | 4:b3c5c54cfd21 | 185 | * data: Data associated with the command |
hudakz | 0:6f3139e3410e | 186 | * @retval |
hudakz | 0:6f3139e3410e | 187 | */ |
hudakz | 0:6f3139e3410e | 188 | void nrfCmd(uint8_t cmd, uint8_t data) { |
hudakz | 0:6f3139e3410e | 189 | |
hudakz | 0:6f3139e3410e | 190 | // Write to nRF24's register |
hudakz | 0:6f3139e3410e | 191 | |
hudakz | 0:6f3139e3410e | 192 | cs = 0; |
hudakz | 0:6f3139e3410e | 193 | spi.write(cmd); |
hudakz | 0:6f3139e3410e | 194 | spi.write(data); |
hudakz | 0:6f3139e3410e | 195 | cs = 1; |
hudakz | 0:6f3139e3410e | 196 | } |
hudakz | 0:6f3139e3410e | 197 | |
hudakz | 0:6f3139e3410e | 198 | /** |
hudakz | 4:b3c5c54cfd21 | 199 | * @brief Transfers one byte to nRF24L01 |
hudakz | 0:6f3139e3410e | 200 | * @note |
hudakz | 4:b3c5c54cfd21 | 201 | * @param cmd: the byte to be transferred |
hudakz | 0:6f3139e3410e | 202 | * @retval |
hudakz | 0:6f3139e3410e | 203 | */ |
hudakz | 0:6f3139e3410e | 204 | void nrfWriteByte(uint8_t cmd) { |
hudakz | 0:6f3139e3410e | 205 | // transfer only one byte |
hudakz | 0:6f3139e3410e | 206 | cs = 0; |
hudakz | 0:6f3139e3410e | 207 | spi.write(cmd); |
hudakz | 0:6f3139e3410e | 208 | cs = 1; |
hudakz | 0:6f3139e3410e | 209 | } |
hudakz | 0:6f3139e3410e | 210 | |
hudakz | 0:6f3139e3410e | 211 | /** |
hudakz | 4:b3c5c54cfd21 | 212 | * @brief Transfers several bytes to nRF24L01 |
hudakz | 0:6f3139e3410e | 213 | * @note |
hudakz | 4:b3c5c54cfd21 | 214 | * @param data: location of bytes to be transferred |
hudakz | 4:b3c5c54cfd21 | 215 | * len: number of bytes to be transferred |
hudakz | 0:6f3139e3410e | 216 | * @retval |
hudakz | 0:6f3139e3410e | 217 | */ |
hudakz | 0:6f3139e3410e | 218 | void nrfWriteBytes(uint8_t* data, uint8_t len) { |
hudakz | 0:6f3139e3410e | 219 | // transfer several bytes in a row |
hudakz | 0:6f3139e3410e | 220 | cs = 0; |
hudakz | 0:6f3139e3410e | 221 | do |
hudakz | 0:6f3139e3410e | 222 | { |
hudakz | 0:6f3139e3410e | 223 | spi.write(*data++); |
hudakz | 0:6f3139e3410e | 224 | } while(--len); |
hudakz | 0:6f3139e3410e | 225 | cs = 1; |
hudakz | 0:6f3139e3410e | 226 | } |
hudakz | 0:6f3139e3410e | 227 | |
hudakz | 0:6f3139e3410e | 228 | int main() { |
hudakz | 5:448e87318747 | 229 | static const uint8_t chRf[] = { 2, 26, 80 }; |
hudakz | 5:448e87318747 | 230 | static const uint8_t chLe[] = { 37, 38, 39 }; |
hudakz | 5:448e87318747 | 231 | |
hudakz | 5:448e87318747 | 232 | uint8_t i = 0; |
hudakz | 5:448e87318747 | 233 | uint8_t j = 0; |
hudakz | 5:448e87318747 | 234 | uint8_t ch = 0; |
hudakz | 5:448e87318747 | 235 | uint8_t data[4]; |
hudakz | 5:448e87318747 | 236 | float* temp = reinterpret_cast <float*>(&data[0]); |
hudakz | 6:14d70104b0fc | 237 | int error = 0; |
hudakz | 0:6f3139e3410e | 238 | |
hudakz | 0:6f3139e3410e | 239 | // Chip must be deselected |
hudakz | 0:6f3139e3410e | 240 | cs = 1; |
hudakz | 0:6f3139e3410e | 241 | |
hudakz | 0:6f3139e3410e | 242 | // Setup the spi for 8 bit data, high steady state clock, |
hudakz | 0:6f3139e3410e | 243 | // second edge capture, with a 10MHz clock rate |
hudakz | 0:6f3139e3410e | 244 | spi.format(8,0); |
hudakz | 0:6f3139e3410e | 245 | spi.frequency(10000000); |
hudakz | 0:6f3139e3410e | 246 | |
hudakz | 0:6f3139e3410e | 247 | ce = 0; |
hudakz | 0:6f3139e3410e | 248 | |
hudakz | 0:6f3139e3410e | 249 | // Initialize nRF24L01+, setting general parameters |
hudakz | 0:6f3139e3410e | 250 | nrfCmd(0x20, 0x12); // on, no crc, int on RX/TX done |
hudakz | 0:6f3139e3410e | 251 | nrfCmd(0x21, 0x00); // no auto-acknowledge |
hudakz | 0:6f3139e3410e | 252 | nrfCmd(0x22, 0x00); // no RX |
hudakz | 0:6f3139e3410e | 253 | nrfCmd(0x23, 0x02); // 4-byte address |
hudakz | 0:6f3139e3410e | 254 | nrfCmd(0x24, 0x00); // no auto-retransmit |
hudakz | 0:6f3139e3410e | 255 | nrfCmd(0x26, 0x06); // 1MBps at 0dBm |
hudakz | 0:6f3139e3410e | 256 | nrfCmd(0x27, 0x3E); // clear various flags |
hudakz | 0:6f3139e3410e | 257 | nrfCmd(0x3C, 0x00); // no dynamic payloads |
hudakz | 0:6f3139e3410e | 258 | nrfCmd(0x3D, 0x00); // no features |
hudakz | 0:6f3139e3410e | 259 | nrfCmd(0x31, 32); // always RX 32 bytes |
hudakz | 0:6f3139e3410e | 260 | nrfCmd(0x22, 0x01); // RX on pipe 0 |
hudakz | 0:6f3139e3410e | 261 | |
hudakz | 0:6f3139e3410e | 262 | // Set access addresses (TX address in nRF24L01) to BLE advertising 0x8E89BED6 |
hudakz | 0:6f3139e3410e | 263 | // Remember that both bit and byte orders are reversed for BLE packet format |
hudakz | 0:6f3139e3410e | 264 | buf[0] = 0x30; |
hudakz | 0:6f3139e3410e | 265 | buf[1] = swapBits(0x8E); |
hudakz | 0:6f3139e3410e | 266 | buf[2] = swapBits(0x89); |
hudakz | 0:6f3139e3410e | 267 | buf[3] = swapBits(0xBE); |
hudakz | 0:6f3139e3410e | 268 | buf[4] = swapBits(0xD6); |
hudakz | 0:6f3139e3410e | 269 | nrfWriteBytes(buf, 5); |
hudakz | 0:6f3139e3410e | 270 | buf[0] = 0x2A; // set RX address in nRF24L01, doesn't matter because RX is ignored in this case |
hudakz | 0:6f3139e3410e | 271 | nrfWriteBytes(buf, 5); |
hudakz | 4:b3c5c54cfd21 | 272 | |
hudakz | 3:96153a5d95f6 | 273 | if(!ds1820.begin()) { |
hudakz | 3:96153a5d95f6 | 274 | #if DEBUG |
hudakz | 3:96153a5d95f6 | 275 | serial.printf("No DS1820 sensor found!\r\n"); |
hudakz | 3:96153a5d95f6 | 276 | #endif |
hudakz | 4:b3c5c54cfd21 | 277 | return 1; |
hudakz | 3:96153a5d95f6 | 278 | } |
hudakz | 0:6f3139e3410e | 279 | |
hudakz | 4:b3c5c54cfd21 | 280 | |
hudakz | 5:448e87318747 | 281 | while(1) { |
hudakz | 6:14d70104b0fc | 282 | ds1820.startConversion(); // Start temperature conversion |
hudakz | 6:14d70104b0fc | 283 | wait(1.0); // let DS1820 complete the temperature conversion |
hudakz | 6:14d70104b0fc | 284 | error = ds1820.read(*temp); // read temperature from DS1820 and perform cyclic redundancy check (CRC) |
hudakz | 2:4f285d1d5c1f | 285 | |
hudakz | 2:4f285d1d5c1f | 286 | #if DEBUG |
hudakz | 6:14d70104b0fc | 287 | switch(error) { |
hudakz | 6:14d70104b0fc | 288 | case 0: // no errors -> '*temp' contains the value of measured temperature |
hudakz | 6:14d70104b0fc | 289 | serial.printf("temp = %3.1f\r\n", *temp); |
hudakz | 6:14d70104b0fc | 290 | break; |
hudakz | 6:14d70104b0fc | 291 | case 1: // no sensor present -> '*temp' is not updated |
hudakz | 6:14d70104b0fc | 292 | serial.printf("no sensor present\n\r"); |
hudakz | 6:14d70104b0fc | 293 | break; |
hudakz | 6:14d70104b0fc | 294 | case 2: // CRC error -> '*temp' is not updated |
hudakz | 6:14d70104b0fc | 295 | serial.printf("CRC error\r\n"); |
hudakz | 6:14d70104b0fc | 296 | } |
hudakz | 2:4f285d1d5c1f | 297 | #endif |
hudakz | 0:6f3139e3410e | 298 | |
hudakz | 0:6f3139e3410e | 299 | buf[i++] = 0x42; // PDU type, given address is random; 0x42 for Android and 0x40 for iPhone |
hudakz | 0:6f3139e3410e | 300 | buf[i++] = 25; // number of following data bytes, max 29 (CRC is not included) |
hudakz | 0:6f3139e3410e | 301 | |
hudakz | 0:6f3139e3410e | 302 | //---------------------------- |
hudakz | 0:6f3139e3410e | 303 | buf[i++] = MY_MAC_0; |
hudakz | 0:6f3139e3410e | 304 | buf[i++] = MY_MAC_1; |
hudakz | 0:6f3139e3410e | 305 | buf[i++] = MY_MAC_2; |
hudakz | 0:6f3139e3410e | 306 | buf[i++] = MY_MAC_3; |
hudakz | 0:6f3139e3410e | 307 | buf[i++] = MY_MAC_4; |
hudakz | 0:6f3139e3410e | 308 | buf[i++] = MY_MAC_5; |
hudakz | 0:6f3139e3410e | 309 | |
hudakz | 0:6f3139e3410e | 310 | buf[i++] = 2; // flags (LE-only, limited discovery mode) |
hudakz | 0:6f3139e3410e | 311 | buf[i++] = 0x01; |
hudakz | 0:6f3139e3410e | 312 | buf[i++] = 0x05; |
hudakz | 0:6f3139e3410e | 313 | |
hudakz | 0:6f3139e3410e | 314 | buf[i++] = 9; // length of the name, including type byte |
hudakz | 0:6f3139e3410e | 315 | buf[i++] = 0x08; // TYPE_NAME_SHORT |
hudakz | 0:6f3139e3410e | 316 | buf[i++] = 'n'; |
hudakz | 0:6f3139e3410e | 317 | buf[i++] = 'R'; |
hudakz | 0:6f3139e3410e | 318 | buf[i++] = 'F'; |
hudakz | 0:6f3139e3410e | 319 | buf[i++] = '2'; |
hudakz | 0:6f3139e3410e | 320 | buf[i++] = '4'; |
hudakz | 0:6f3139e3410e | 321 | buf[i++] = 'L'; |
hudakz | 0:6f3139e3410e | 322 | buf[i++] = '0'; |
hudakz | 0:6f3139e3410e | 323 | buf[i++] = '1'; |
hudakz | 0:6f3139e3410e | 324 | |
hudakz | 0:6f3139e3410e | 325 | buf[i++] = 5; // length of custom data, including type byte |
hudakz | 0:6f3139e3410e | 326 | buf[i++] = 0xff; // TYPE_CUSTOMDATA |
hudakz | 0:6f3139e3410e | 327 | |
hudakz | 0:6f3139e3410e | 328 | buf[i++] = data[0]; // temperature floating point value (four bytes) |
hudakz | 0:6f3139e3410e | 329 | buf[i++] = data[1]; |
hudakz | 0:6f3139e3410e | 330 | buf[i++] = data[2]; |
hudakz | 0:6f3139e3410e | 331 | buf[i++] = data[3]; |
hudakz | 0:6f3139e3410e | 332 | //---------------------------- |
hudakz | 0:6f3139e3410e | 333 | |
hudakz | 0:6f3139e3410e | 334 | buf[i++] = 0x55; // CRC start value: 0x555555 |
hudakz | 0:6f3139e3410e | 335 | buf[i++] = 0x55; |
hudakz | 0:6f3139e3410e | 336 | buf[i++] = 0x55; |
hudakz | 0:6f3139e3410e | 337 | |
hudakz | 0:6f3139e3410e | 338 | // Channel hopping |
hudakz | 0:6f3139e3410e | 339 | if(++ch == sizeof(chRf)) |
hudakz | 0:6f3139e3410e | 340 | ch = 0; |
hudakz | 0:6f3139e3410e | 341 | nrfCmd(0x25, chRf[ch]); |
hudakz | 0:6f3139e3410e | 342 | nrfCmd(0x27, 0x6E); // Clear flags |
hudakz | 0:6f3139e3410e | 343 | blePacketEncode(buf, i, chLe[ch]); |
hudakz | 0:6f3139e3410e | 344 | nrfWriteByte(0xE2); // Clear RX Fifo |
hudakz | 0:6f3139e3410e | 345 | nrfWriteByte(0xE1); // Clear TX Fifo |
hudakz | 2:4f285d1d5c1f | 346 | |
hudakz | 0:6f3139e3410e | 347 | cs = 0; |
hudakz | 0:6f3139e3410e | 348 | spi.write(0xA0); |
hudakz | 0:6f3139e3410e | 349 | for(j = 0; j < i; j++) |
hudakz | 0:6f3139e3410e | 350 | spi.write(buf[j]); |
hudakz | 0:6f3139e3410e | 351 | cs = 1; |
hudakz | 0:6f3139e3410e | 352 | |
hudakz | 0:6f3139e3410e | 353 | nrfCmd(0x20, 0x12); // TX on |
hudakz | 0:6f3139e3410e | 354 | ce = 1; // Enable Chip |
hudakz | 0:6f3139e3410e | 355 | wait_ms(50); |
hudakz | 0:6f3139e3410e | 356 | ce = 0; // (in preparation of switching to RX quickly) |
hudakz | 0:6f3139e3410e | 357 | } |
hudakz | 0:6f3139e3410e | 358 | } |