|
| 1 | +#include <msp430.h> |
| 2 | +#include <stdio.h> |
| 3 | +#include <stdint.h> |
| 4 | + |
| 5 | +/* |
| 6 | +Demo code to continuously read and display temperature and humidity data from TI HDC2010 using MSP430F5529 Launchpad. |
| 7 | +Device is periodically polled by the MCU in on-demand mode. No temp or humidity threshold interrupts. |
| 8 | +Low-level I2C communication using registers, interrupts, and MCU LPM0 mode. Display data on terminal program. |
| 9 | +Temperature resolution: 14-bit and displayed with 4 significant figures. |
| 10 | +Humidity resolution: 11-bit displayed with 3 significant figures. Ground the ADR pin to set slave address at 0X40. |
| 11 | +Sensor is briefly heated at startup/reset; heater draws 90 mA at 3.3V |
| 12 | +Main loop runs with timed interrupt from LPM3 and VLO clock. I2C clock 100 kHz; UART 9600 baud. |
| 13 | +IDE with CCS 6.1.3 and nofloat printf support. |
| 14 | +
|
| 15 | +P3.0 SDA with 10k pullup |
| 16 | +P3.1 SCL with 10k pullup |
| 17 | +P3.3 TXD |
| 18 | +P3.4 RXD |
| 19 | +
|
| 20 | +September 2018 |
| 21 | + */ |
| 22 | +# define PERIOD 10000 //Samping period. 10000 count is approximately 1 second; maximum is 65535 |
| 23 | +# define HEATER 20000 //Pulse heater at reset. 20000 count is approximately 2 seconds |
| 24 | + |
| 25 | +void SetTimer(void); |
| 26 | +void SetVLO(void); |
| 27 | +void SetPins(void); |
| 28 | +void SetUART(void); |
| 29 | +void SetI2C(void); |
| 30 | +void Measure(void); |
| 31 | +void GetData(void); |
| 32 | +void Heater(void); |
| 33 | + |
| 34 | +//Variables for I2C communication |
| 35 | +volatile uint8_t *PTxData; // Pointer to TX data |
| 36 | +volatile uint8_t TXByteCtr; |
| 37 | +volatile uint8_t *PRxData; // Pointer to RX data |
| 38 | +volatile uint8_t RXByteCtr; |
| 39 | +volatile uint8_t RxBuffer[4]; // Allocate 4 bytes of RAM for data |
| 40 | + |
| 41 | +//Variables for UART terminal display |
| 42 | +char str[80]; |
| 43 | +volatile uint32_t T,TC,H,HC; |
| 44 | +volatile uint8_t i,count; |
| 45 | + |
| 46 | +void main(void) { |
| 47 | + |
| 48 | + WDTCTL = WDTPW | WDTHOLD; //Stop watchdog timer |
| 49 | + |
| 50 | + SetPins(); |
| 51 | + SetVLO(); |
| 52 | + SetTimer(); |
| 53 | + SetUART(); |
| 54 | + SetI2C(); |
| 55 | + |
| 56 | + _BIS_SR(GIE); //Enable global interrupts |
| 57 | + Heater(); //Comment this line to prevent heating after reset |
| 58 | + |
| 59 | + while(1) |
| 60 | + { |
| 61 | + TA0CCR0 = PERIOD; //Looping period with VLO |
| 62 | + LPM3; //Wait in low power mode |
| 63 | + P4OUT |= BIT7; //Timeout. Turn on green LED on Launchpad |
| 64 | + |
| 65 | + UCB0IE |= UCTXIE + UCRXIE; //Enable TX and RX I2C interrupts |
| 66 | + Measure(); //Initiate measurement. No need to poll or wait for data |
| 67 | + GetData(); //Get T-H data |
| 68 | + |
| 69 | + UCB0IE &= ~(UCRXIE + UCTXIE); //Disable I2C interrupts |
| 70 | + |
| 71 | + //Process 16-bit raw temperature data |
| 72 | + T = ((uint16_t)(*(PRxData+2)) << 8)|(uint16_t)*(PRxData+3); |
| 73 | + //Convert temperature data |
| 74 | + TC = (((T<<14) + (T<<8) - (T<<7) - (T<<3) - (T<<2)) >> 16) - 0xFA0; //No decimal point |
| 75 | + |
| 76 | + //Process 16-bit raw humidity data |
| 77 | + H = (uint16_t)(*PRxData << 8)|(uint16_t)*(PRxData+1); |
| 78 | + //Convert temperature data |
| 79 | + HC = ((H<<10) - (H<<4) - (H<<3)) >> 16; //No decimal point |
| 80 | +/* |
| 81 | + //Display on terminal |
| 82 | + sprintf(str1,"%s %lu %s %lu %s", "Raw temp:", T, "Raw humid:", H,"\r\n"); |
| 83 | + count = sizeof str1; |
| 84 | + for (i=0; i < count; i++) |
| 85 | + { |
| 86 | + while (!(UCA0IFG & UCTXIFG)); //Poll serial: USCI_A0 TX buffer ready? |
| 87 | + UCA0TXBUF = str1[i]; //Send data 1 byte at a time |
| 88 | + } |
| 89 | +*/ |
| 90 | + |
| 91 | + sprintf(str,"%s %lu.%.2lu%s %lu.%.1lu%s", "Temp:", (int32_t)(TC/100),(int32_t)(TC%100),"C Rel Humidity:", |
| 92 | + (int32_t)(HC/10),(int32_t)(HC%10),"%\r\n\n"); |
| 93 | + count = sizeof str; |
| 94 | + for (i=0; i < count; i++) |
| 95 | + { |
| 96 | + while (!(UCA0IFG & UCTXIFG)); //Poll serial: USCI_A0 TX buffer ready? |
| 97 | + UCA0TXBUF = str[i]; //Send data 1 byte at a time |
| 98 | + } |
| 99 | + P4OUT &= ~BIT7; //Turn off green LED |
| 100 | + } |
| 101 | +} |
| 102 | + |
| 103 | +#pragma vector=TIMER0_A0_VECTOR |
| 104 | + __interrupt void timerfoo (void) |
| 105 | +{ |
| 106 | + LPM3_EXIT; |
| 107 | +} |
| 108 | + |
| 109 | +#pragma vector = USCI_B0_VECTOR |
| 110 | +__interrupt void USCI_B0_ISR(void) |
| 111 | +{ |
| 112 | + switch(__even_in_range(UCB0IV,12)) |
| 113 | + { |
| 114 | + case 0: break; // Vector 0: No interrupts |
| 115 | + case 2: break; // Vector 2: ALIFG |
| 116 | + case 4: break; // Vector 4: NACKIFG |
| 117 | + case 6: break; // Vector 6: STTIFG |
| 118 | + case 8: break; // Vector 8: STPIF |
| 119 | + case 10: |
| 120 | + RXByteCtr--; // Decrement RX byte counter |
| 121 | + if (RXByteCtr) |
| 122 | + { |
| 123 | + *(PRxData + RXByteCtr) = UCB0RXBUF; // Move RX data to address PRxData |
| 124 | + if (RXByteCtr == 1) // Only one byte left? |
| 125 | + UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition |
| 126 | + } |
| 127 | + else |
| 128 | + { |
| 129 | + *PRxData = UCB0RXBUF; // Move final RX data to PRxData(0) |
| 130 | + LPM0_EXIT; // Exit active CPU |
| 131 | + } |
| 132 | + break; |
| 133 | + case 12: // Vector 12: TXIFG |
| 134 | + if (TXByteCtr) // Check TX byte counter |
| 135 | + { |
| 136 | + UCB0TXBUF = *PTxData++; // Load TX buffer |
| 137 | + TXByteCtr--; // Decrement TX byte counter |
| 138 | + } |
| 139 | + else |
| 140 | + { |
| 141 | + UCB0CTL1 |= UCTXSTP; // I2C stop condition |
| 142 | + UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag |
| 143 | + LPM0_EXIT; // Exit LPM0 |
| 144 | + } |
| 145 | + break; |
| 146 | + default: break; |
| 147 | + } |
| 148 | +} |
| 149 | + |
| 150 | + void SetPins(void) |
| 151 | + { |
| 152 | + /* Port 1 |
| 153 | + * P1.0 Red LED |
| 154 | + */ |
| 155 | + P1DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7; |
| 156 | + P1OUT &= ~BIT0; //LED off |
| 157 | + |
| 158 | + /* Port 2 |
| 159 | + P2.1 Button on Launchpad |
| 160 | + */ |
| 161 | + P2DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7; |
| 162 | + |
| 163 | + /* Port 3 */ |
| 164 | + /* |
| 165 | + * P3.0 SDA |
| 166 | + * P3.1 SCL |
| 167 | + * P3.3 TXD |
| 168 | + * P3.4 RXD |
| 169 | + */ |
| 170 | + P3SEL |= BIT0 + BIT1 + BIT3 + BIT4; //Set the I2C and UART lines |
| 171 | + P3DIR |= BIT2 + BIT5 + BIT6 + BIT7; |
| 172 | + |
| 173 | + /* Port 4 |
| 174 | + P4.1 -- 4.6 unused |
| 175 | + P4.7 Green LED |
| 176 | + */ |
| 177 | + P4DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7; |
| 178 | + P4OUT &= ~BIT7; //Green LED off |
| 179 | + |
| 180 | + /* Port 5 |
| 181 | + P5.0 Unused |
| 182 | + P5.1 Unused |
| 183 | + P5.2--P5.5 grounded or open as per spec sheet |
| 184 | + */ |
| 185 | + P5DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7; |
| 186 | + |
| 187 | + /* Port 6 |
| 188 | + P6.0--6.7 unused |
| 189 | + */ |
| 190 | + P6DIR |= BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + BIT7; |
| 191 | + } |
| 192 | + |
| 193 | + void SetVLO(void) |
| 194 | + { //Default frequency ~ 10 kHz |
| 195 | + UCSCTL4 |= SELA_1; //Set ACLK to VLO |
| 196 | + } |
| 197 | + |
| 198 | + void SetTimer(void) |
| 199 | + { |
| 200 | + TA0CCTL0 |= CCIE; //Enable timer interrupt |
| 201 | + TA0CTL = TASSEL_1 | MC_1; //Set Timer A to ACLK; MC_1 to count up to TA0CCR0. |
| 202 | + } |
| 203 | + |
| 204 | + void SetUART(void) //Do simple polling instead of interrupts |
| 205 | + { |
| 206 | + UCA0CTL1 |= UCSWRST; // **Put state machine in reset** |
| 207 | + UCA0CTL1 |= UCSSEL_2; // SMCLK |
| 208 | + UCA0BR0 = 6; // 1MHz 9600 |
| 209 | + UCA0BR1 = 0; // 1MHz 9600 |
| 210 | + UCA0MCTL = UCBRS_0 + UCBRF_13 + UCOS16; // Modln UCBRSx=0, UCBRFx=0, |
| 211 | + UCA0CTL1 &= ~UCSWRST; // **Initialize USCI state machine** |
| 212 | + } |
| 213 | + |
| 214 | + void SetI2C(void) |
| 215 | + { |
| 216 | + // Configure the USCI B0 module for I2C at 100 kHz |
| 217 | + UCB0CTL1 |= UCSWRST; |
| 218 | + UCB0CTL0 |= UCMST + UCSYNC + UCMODE_3; //Set as master, synchronous, UCMODE_3 for I2C |
| 219 | + UCB0CTL1 = UCSSEL_2 + UCSWRST; //Select SMCLK |
| 220 | + UCB0BR0 = 12; //Next 2 lines set SMCLK to 100 kHz |
| 221 | + UCB0BR1 = 0; |
| 222 | + UCB0I2CSA = 0x40; // HDC2010 address; ADR grounded |
| 223 | + UCB0CTL1 &= ~UCSWRST; // Clear reset |
| 224 | + } |
| 225 | + |
| 226 | + void Heater(void) |
| 227 | + { |
| 228 | + UCB0IE |= UCTXIE; //Enable I2C TX interrupt |
| 229 | + const uint8_t HT[] = {0x0E,0x08}; //Heater activation command |
| 230 | + UCB0CTL1 |= UCTR; |
| 231 | + PTxData = (uint8_t *)HT; |
| 232 | + TXByteCtr = 2; |
| 233 | + UCB0CTL1 |= UCTXSTT; |
| 234 | + LPM0; // MCU Remain in LPM0 until all data transmitted |
| 235 | + P1OUT |= BIT0; //Heater is on. Turn on red LED on Launchpad |
| 236 | + TA0CCR0 = HEATER; //Heater on time. |
| 237 | + LPM3; //MCU waits in low power mode |
| 238 | + |
| 239 | + const uint8_t HO[] = {0x0E,0x00}; //Heater deactivation |
| 240 | + UCB0CTL1 |= UCTR; |
| 241 | + PTxData = (uint8_t *)HO; |
| 242 | + TXByteCtr = 2; |
| 243 | + UCB0CTL1 |= UCTXSTT; |
| 244 | + LPM0; |
| 245 | + UCB0IE &= ~UCTXIE; //Disable I2C TX interrupt |
| 246 | + P1OUT &= ~BIT0; //Turn off red LED |
| 247 | + |
| 248 | + } |
| 249 | + |
| 250 | + void Measure(void) |
| 251 | + { |
| 252 | + //Initiates a temp-humid measurement with 14- and 11-bit resolution, respectively |
| 253 | + const uint8_t MS[] = {0x0F,0x11}; |
| 254 | + UCB0CTL1 |= UCTR; //Set as transmitter |
| 255 | + PTxData = (uint8_t *)MS; // TX array start address |
| 256 | + TXByteCtr = 2; // Load TX byte counter |
| 257 | + UCB0CTL1 |= UCTXSTT; // Start condition |
| 258 | + LPM0; // Remain in LPM0 until all data transmitted |
| 259 | + } |
| 260 | + |
| 261 | + |
| 262 | + void GetData(void) |
| 263 | + { |
| 264 | + const uint8_t ReadData[] = {0x00,0x01,0x02,0x03}; //Read the 4 data bytes |
| 265 | + UCB0CTL1 |= UCTR; //Set as transmitter |
| 266 | + PTxData = (uint8_t *)ReadData; // TX array start address |
| 267 | + TXByteCtr = 4; // Load TX byte counter |
| 268 | + UCB0CTL1 |= UCTXSTT; // Start condition |
| 269 | + LPM0; // Remain in LPM0 until all data transmitted |
| 270 | + while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent |
| 271 | + //Receive 4 data bytes |
| 272 | + UCB0CTL1 &= ~UCTR; //Set as receiver |
| 273 | + PRxData = (uint8_t *)RxBuffer; // Start of RX buffer |
| 274 | + RXByteCtr = 4; |
| 275 | + UCB0CTL1 |= UCTXSTT; // I2C start condition |
| 276 | + LPM0; |
| 277 | + } |
| 278 | + |
| 279 | + |
0 commit comments