Quick test of the Wi-Go Magnetometer

Dependencies:   TSI mbed MAG3110

Committer:
SomeRandomBloke
Date:
Thu May 16 22:11:33 2013 +0000
Revision:
0:26bfff579f01
Child:
1:d45fc466a46e
initial

Who changed what in which revision?

UserRevisionLine numberNew contents of line
SomeRandomBloke 0:26bfff579f01 1 #include "mbed.h"
SomeRandomBloke 0:26bfff579f01 2 #include "math.h"
SomeRandomBloke 0:26bfff579f01 3
SomeRandomBloke 0:26bfff579f01 4 //PwmOut r (LED_RED);
SomeRandomBloke 0:26bfff579f01 5 //PwmOut g (LED_GREEN);
SomeRandomBloke 0:26bfff579f01 6 //PwmOut b (LED_BLUE);
SomeRandomBloke 0:26bfff579f01 7
SomeRandomBloke 0:26bfff579f01 8
SomeRandomBloke 0:26bfff579f01 9
SomeRandomBloke 0:26bfff579f01 10 #define MAG_ADDR 0x1D
SomeRandomBloke 0:26bfff579f01 11 // (0x0E << 1)
SomeRandomBloke 0:26bfff579f01 12 //0x1D
SomeRandomBloke 0:26bfff579f01 13
SomeRandomBloke 0:26bfff579f01 14 // define register values
SomeRandomBloke 0:26bfff579f01 15 #define MAG_DR_STATUS 0x00
SomeRandomBloke 0:26bfff579f01 16 #define MAG_OUT_X_MSB 0x01
SomeRandomBloke 0:26bfff579f01 17 #define MAG_OUT_X_LSB 0x02
SomeRandomBloke 0:26bfff579f01 18 #define MAG_OUT_Y_MSB 0x03
SomeRandomBloke 0:26bfff579f01 19 #define MAG_OUT_Y_LSB 0x04
SomeRandomBloke 0:26bfff579f01 20 #define MAG_OUT_Z_MSB 0x05
SomeRandomBloke 0:26bfff579f01 21 #define MAG_OUT_Z_LSB 0x06
SomeRandomBloke 0:26bfff579f01 22 #define MAG_WHO_AM_I 0x07
SomeRandomBloke 0:26bfff579f01 23 #define MAG_SYSMOD 0x08
SomeRandomBloke 0:26bfff579f01 24 #define MAG_OFF_X_MSB 0x09
SomeRandomBloke 0:26bfff579f01 25 #define MAG_OFF_X_LSB 0x0A
SomeRandomBloke 0:26bfff579f01 26 #define MAG_OFF_Y_MSB 0x0B
SomeRandomBloke 0:26bfff579f01 27 #define MAG_OFF_Y_LSB 0x0C
SomeRandomBloke 0:26bfff579f01 28 #define MAG_OFF_Z_MSB 0x0D
SomeRandomBloke 0:26bfff579f01 29 #define MAG_OFF_Z_LSB 0x0E
SomeRandomBloke 0:26bfff579f01 30 #define MAG_DIE_TEMP 0x0F
SomeRandomBloke 0:26bfff579f01 31 #define MAG_CTRL_REG1 0x10
SomeRandomBloke 0:26bfff579f01 32 #define MAG_CTRL_REG2 0x11
SomeRandomBloke 0:26bfff579f01 33
SomeRandomBloke 0:26bfff579f01 34 // what should WHO_AM_I return?
SomeRandomBloke 0:26bfff579f01 35 #define MAG_3110_WHO_AM_I_VALUE 0xC4
SomeRandomBloke 0:26bfff579f01 36
SomeRandomBloke 0:26bfff579f01 37
SomeRandomBloke 0:26bfff579f01 38 // Fields in registers
SomeRandomBloke 0:26bfff579f01 39 // CTRL_REG1: dr2,dr1,dr0 os1,os0 fr tm ac
SomeRandomBloke 0:26bfff579f01 40
SomeRandomBloke 0:26bfff579f01 41 // Sampling rate from 80Hz down to 0.625Hz
SomeRandomBloke 0:26bfff579f01 42 #define MAG_3110_SAMPLE80 0
SomeRandomBloke 0:26bfff579f01 43 #define MAG_3110_SAMPLE40 0x20
SomeRandomBloke 0:26bfff579f01 44 #define MAG_3110_SAMPLE20 0x40
SomeRandomBloke 0:26bfff579f01 45 #define MAG_3110_SAMPLE10 0x60
SomeRandomBloke 0:26bfff579f01 46 #define MAG_3110_SAMPLE5 0x80
SomeRandomBloke 0:26bfff579f01 47 #define MAG_3110_SAMPLE2_5 0xA0
SomeRandomBloke 0:26bfff579f01 48 #define MAG_3110_SAMPLE1_25 0xC0
SomeRandomBloke 0:26bfff579f01 49 #define MAG_3110_SAMPLE0_625 0xE0
SomeRandomBloke 0:26bfff579f01 50
SomeRandomBloke 0:26bfff579f01 51 // How many samples to average (lowers data rate)
SomeRandomBloke 0:26bfff579f01 52 #define MAG_3110_OVERSAMPLE1 0
SomeRandomBloke 0:26bfff579f01 53 #define MAG_3110_OVERSAMPLE2 0x08
SomeRandomBloke 0:26bfff579f01 54 #define MAG_3110_OVERSAMPLE3 0x10
SomeRandomBloke 0:26bfff579f01 55 #define MAG_3110_OVERSAMPLE4 0x18
SomeRandomBloke 0:26bfff579f01 56
SomeRandomBloke 0:26bfff579f01 57 // read only 1 byte per axis
SomeRandomBloke 0:26bfff579f01 58 #define MAG_3110_FASTREAD 0x04
SomeRandomBloke 0:26bfff579f01 59 // do one measurement (even if in standby mode)
SomeRandomBloke 0:26bfff579f01 60 #define MAG_3110_TRIGGER 0x02
SomeRandomBloke 0:26bfff579f01 61 // put in active mode
SomeRandomBloke 0:26bfff579f01 62 #define MAG_3110_ACTIVE 0x01
SomeRandomBloke 0:26bfff579f01 63
SomeRandomBloke 0:26bfff579f01 64 // CTRL_REG2: AUTO_MRST_EN _ RAW MAG_RST _ _ _ _ _
SomeRandomBloke 0:26bfff579f01 65 // reset sensor after each reading
SomeRandomBloke 0:26bfff579f01 66 #define MAG_3110_AUTO_MRST_EN 0x80
SomeRandomBloke 0:26bfff579f01 67 // don't subtract user offsets
SomeRandomBloke 0:26bfff579f01 68 #define MAG_3110_RAW 0x20
SomeRandomBloke 0:26bfff579f01 69 // reset magnetic sensor after too-large field
SomeRandomBloke 0:26bfff579f01 70 #define MAG_3110_MAG_RST 0x10
SomeRandomBloke 0:26bfff579f01 71
SomeRandomBloke 0:26bfff579f01 72 // DR_STATUS Register ZYXOW ZOW YOW XOW ZYXDR ZDR YDR XDR
SomeRandomBloke 0:26bfff579f01 73 #define MAG_3110_ZYXDR 0x08
SomeRandomBloke 0:26bfff579f01 74
SomeRandomBloke 0:26bfff579f01 75
SomeRandomBloke 0:26bfff579f01 76 //0x0E //7-bit address for the MAG3110, doesn't change
SomeRandomBloke 0:26bfff579f01 77
SomeRandomBloke 0:26bfff579f01 78 DigitalOut myled(PTB10);
SomeRandomBloke 0:26bfff579f01 79 DigitalOut redLed(LED_RED);
SomeRandomBloke 0:26bfff579f01 80 DigitalOut greenLed(LED_GREEN);
SomeRandomBloke 0:26bfff579f01 81 DigitalOut blueLed(LED_BLUE);
SomeRandomBloke 0:26bfff579f01 82
SomeRandomBloke 0:26bfff579f01 83 I2C i2c(PTE0, PTE1);
SomeRandomBloke 0:26bfff579f01 84
SomeRandomBloke 0:26bfff579f01 85 int avgX, avgY, newX, tempXmin, tempXmax, newY, tempYmin, tempYmax;
SomeRandomBloke 0:26bfff579f01 86 struct settings_t {
SomeRandomBloke 0:26bfff579f01 87 long maxX, minX, maxY, minY;
SomeRandomBloke 0:26bfff579f01 88 }
SomeRandomBloke 0:26bfff579f01 89 settings;
SomeRandomBloke 0:26bfff579f01 90
SomeRandomBloke 0:26bfff579f01 91 const int addr = MAG_ADDR;
SomeRandomBloke 0:26bfff579f01 92
SomeRandomBloke 0:26bfff579f01 93 // Read a single byte form 8 bit register, return as int
SomeRandomBloke 0:26bfff579f01 94 int readReg(char regAddr)
SomeRandomBloke 0:26bfff579f01 95 {
SomeRandomBloke 0:26bfff579f01 96 char cmd[1];
SomeRandomBloke 0:26bfff579f01 97
SomeRandomBloke 0:26bfff579f01 98 cmd[0] = regAddr;
SomeRandomBloke 0:26bfff579f01 99 i2c.write(addr, cmd, 1);
SomeRandomBloke 0:26bfff579f01 100
SomeRandomBloke 0:26bfff579f01 101 cmd[0] = 0x00;
SomeRandomBloke 0:26bfff579f01 102 i2c.read(addr, cmd, 1);
SomeRandomBloke 0:26bfff579f01 103 return (int)( cmd[0]);
SomeRandomBloke 0:26bfff579f01 104
SomeRandomBloke 0:26bfff579f01 105 }
SomeRandomBloke 0:26bfff579f01 106
SomeRandomBloke 0:26bfff579f01 107
SomeRandomBloke 0:26bfff579f01 108 // read a register per, pass first reg value, reading 2 bytes increments register
SomeRandomBloke 0:26bfff579f01 109 // Reads MSB first then LSB
SomeRandomBloke 0:26bfff579f01 110 int readVal(char regAddr)
SomeRandomBloke 0:26bfff579f01 111 {
SomeRandomBloke 0:26bfff579f01 112 char cmd[2];
SomeRandomBloke 0:26bfff579f01 113
SomeRandomBloke 0:26bfff579f01 114 cmd[0] = regAddr;
SomeRandomBloke 0:26bfff579f01 115 i2c.write(addr, cmd, 1);
SomeRandomBloke 0:26bfff579f01 116
SomeRandomBloke 0:26bfff579f01 117 cmd[0] = 0x00;
SomeRandomBloke 0:26bfff579f01 118 cmd[1] = 0x00;
SomeRandomBloke 0:26bfff579f01 119 i2c.read(addr, cmd, 2);
SomeRandomBloke 0:26bfff579f01 120 return (int)( (cmd[1]|(cmd[0] << 8))); //concatenate the MSB and LSB
SomeRandomBloke 0:26bfff579f01 121 }
SomeRandomBloke 0:26bfff579f01 122
SomeRandomBloke 0:26bfff579f01 123 #define PI 3.14159265359
SomeRandomBloke 0:26bfff579f01 124
SomeRandomBloke 0:26bfff579f01 125
SomeRandomBloke 0:26bfff579f01 126 void calXY() //magnetometer calibration: finding max and min of X, Y axis
SomeRandomBloke 0:26bfff579f01 127 {
SomeRandomBloke 0:26bfff579f01 128 int tempXmax, tempXmin, tempYmax, tempYmin, newX, newY;
SomeRandomBloke 0:26bfff579f01 129 redLed = 0;
SomeRandomBloke 0:26bfff579f01 130 // lcd.setCursor(0,1);
SomeRandomBloke 0:26bfff579f01 131 // lcd.print(“Rotate the car “);
SomeRandomBloke 0:26bfff579f01 132 // delay(1000);
SomeRandomBloke 0:26bfff579f01 133 // lcd.setCursor(0,1);
SomeRandomBloke 0:26bfff579f01 134 // lcd.print(“and press button”);
SomeRandomBloke 0:26bfff579f01 135 // delay(1000);
SomeRandomBloke 0:26bfff579f01 136 // lcd.setCursor(0,1);
SomeRandomBloke 0:26bfff579f01 137 // lcd.print(“Now, begin! “);
SomeRandomBloke 0:26bfff579f01 138 // delay(500);
SomeRandomBloke 0:26bfff579f01 139 tempXmax = tempXmin = readVal(MAG_OUT_X_MSB);
SomeRandomBloke 0:26bfff579f01 140 tempYmax = tempYmin = readVal(MAG_OUT_Y_MSB);
SomeRandomBloke 0:26bfff579f01 141 int changeCount = 10000;
SomeRandomBloke 0:26bfff579f01 142 bool change = false;
SomeRandomBloke 0:26bfff579f01 143 while(changeCount) { // digitalRead(10) == LOW) {
SomeRandomBloke 0:26bfff579f01 144 // for(int x=0; x<100000; x++); {
SomeRandomBloke 0:26bfff579f01 145 //newX = readx();
SomeRandomBloke 0:26bfff579f01 146 //newY = ready();
SomeRandomBloke 0:26bfff579f01 147 newX = readVal(MAG_OUT_X_MSB);
SomeRandomBloke 0:26bfff579f01 148 newY = readVal(MAG_OUT_Y_MSB);
SomeRandomBloke 0:26bfff579f01 149 if (newX > tempXmax) {
SomeRandomBloke 0:26bfff579f01 150 tempXmax = newX;
SomeRandomBloke 0:26bfff579f01 151 change = true;
SomeRandomBloke 0:26bfff579f01 152 }
SomeRandomBloke 0:26bfff579f01 153 if (newX < tempXmin) {
SomeRandomBloke 0:26bfff579f01 154 tempXmin = newX;
SomeRandomBloke 0:26bfff579f01 155 change = true;
SomeRandomBloke 0:26bfff579f01 156 }
SomeRandomBloke 0:26bfff579f01 157 if (newY > tempYmax) {
SomeRandomBloke 0:26bfff579f01 158 tempYmax = newY;
SomeRandomBloke 0:26bfff579f01 159 change = true;
SomeRandomBloke 0:26bfff579f01 160 }
SomeRandomBloke 0:26bfff579f01 161 if (newY < tempYmin) {
SomeRandomBloke 0:26bfff579f01 162 tempYmin = newY;
SomeRandomBloke 0:26bfff579f01 163 change = true;
SomeRandomBloke 0:26bfff579f01 164 }
SomeRandomBloke 0:26bfff579f01 165 if( change )
SomeRandomBloke 0:26bfff579f01 166 change = false;
SomeRandomBloke 0:26bfff579f01 167 else
SomeRandomBloke 0:26bfff579f01 168 changeCount--;
SomeRandomBloke 0:26bfff579f01 169 // printf("X max %d min %d, Y max %d min %d\n",tempXmax, tempXmin, tempYmax, tempYmin);
SomeRandomBloke 0:26bfff579f01 170 }
SomeRandomBloke 0:26bfff579f01 171 settings.maxX = tempXmax;
SomeRandomBloke 0:26bfff579f01 172 settings.minX = tempXmin;
SomeRandomBloke 0:26bfff579f01 173 settings.maxY = tempYmax;
SomeRandomBloke 0:26bfff579f01 174 settings.minY = tempYmin;
SomeRandomBloke 0:26bfff579f01 175 //X max 65173 min 64850, Y max 490 min 141
SomeRandomBloke 0:26bfff579f01 176
SomeRandomBloke 0:26bfff579f01 177 //store new X, Y values in the EEPROM
SomeRandomBloke 0:26bfff579f01 178 // eeprom_write_block((const void*)&settings, (void*)0, sizeof(settings));
SomeRandomBloke 0:26bfff579f01 179
SomeRandomBloke 0:26bfff579f01 180 avgX=(settings.maxX+settings.minX)/2;
SomeRandomBloke 0:26bfff579f01 181 avgY=(settings.maxY+settings.minY)/2;
SomeRandomBloke 0:26bfff579f01 182
SomeRandomBloke 0:26bfff579f01 183 redLed = 1;
SomeRandomBloke 0:26bfff579f01 184 // lcd.setCursor(0,1);
SomeRandomBloke 0:26bfff579f01 185 // lcd.print(“Calibration done”);
SomeRandomBloke 0:26bfff579f01 186 //delay(3000);
SomeRandomBloke 0:26bfff579f01 187 // lcd.setCursor(0,1);
SomeRandomBloke 0:26bfff579f01 188 // lcd.print(” “);
SomeRandomBloke 0:26bfff579f01 189
SomeRandomBloke 0:26bfff579f01 190 }
SomeRandomBloke 0:26bfff579f01 191
SomeRandomBloke 0:26bfff579f01 192 int main()
SomeRandomBloke 0:26bfff579f01 193 {
SomeRandomBloke 0:26bfff579f01 194 char cmd[2];
SomeRandomBloke 0:26bfff579f01 195 // r.period(0.001);
SomeRandomBloke 0:26bfff579f01 196 // g.period(0.001);
SomeRandomBloke 0:26bfff579f01 197 // b.period(0.001);
SomeRandomBloke 0:26bfff579f01 198
SomeRandomBloke 0:26bfff579f01 199 printf("MAG3110 Test\n");
SomeRandomBloke 0:26bfff579f01 200
SomeRandomBloke 0:26bfff579f01 201 redLed = 1;
SomeRandomBloke 0:26bfff579f01 202 greenLed = 1;
SomeRandomBloke 0:26bfff579f01 203 blueLed = 1;
SomeRandomBloke 0:26bfff579f01 204
SomeRandomBloke 0:26bfff579f01 205 cmd[0] = MAG_CTRL_REG2;
SomeRandomBloke 0:26bfff579f01 206 cmd[1] = 0x80;
SomeRandomBloke 0:26bfff579f01 207 i2c.write(addr, cmd, 2);
SomeRandomBloke 0:26bfff579f01 208
SomeRandomBloke 0:26bfff579f01 209 // wait(0.1);
SomeRandomBloke 0:26bfff579f01 210 cmd[0] = MAG_CTRL_REG1;
SomeRandomBloke 0:26bfff579f01 211 cmd[1] = MAG_3110_SAMPLE80+MAG_3110_OVERSAMPLE2+MAG_3110_ACTIVE; // 0x91;
SomeRandomBloke 0:26bfff579f01 212 i2c.write(addr, cmd, 2);
SomeRandomBloke 0:26bfff579f01 213
SomeRandomBloke 0:26bfff579f01 214 // Get some values
SomeRandomBloke 0:26bfff579f01 215 printf("DR_STATUS %X\n", readReg( MAG_DR_STATUS ));
SomeRandomBloke 0:26bfff579f01 216 printf("WHO_AM_I %X\n", readReg( MAG_WHO_AM_I ));
SomeRandomBloke 0:26bfff579f01 217 printf("SYSMOD %X\n", readReg( MAG_SYSMOD ));
SomeRandomBloke 0:26bfff579f01 218 printf("DIE_TEMP %d\n", readReg( MAG_DIE_TEMP ));
SomeRandomBloke 0:26bfff579f01 219
SomeRandomBloke 0:26bfff579f01 220 printf("OFF_X %d\n", readVal( MAG_OFF_X_MSB ));
SomeRandomBloke 0:26bfff579f01 221 printf("OFF_Y %d\n", readVal( MAG_OFF_Y_MSB ));
SomeRandomBloke 0:26bfff579f01 222 printf("OFF_Z %d\n", readVal( MAG_OFF_Z_MSB ));
SomeRandomBloke 0:26bfff579f01 223
SomeRandomBloke 0:26bfff579f01 224 printf("CTRL_REG1 %X\n", readReg( MAG_CTRL_REG1 ));
SomeRandomBloke 0:26bfff579f01 225 printf("CTRL_REG2 %X\n", readReg( MAG_CTRL_REG2 ));
SomeRandomBloke 0:26bfff579f01 226
SomeRandomBloke 0:26bfff579f01 227 // r = 1;
SomeRandomBloke 0:26bfff579f01 228 // g = 0;
SomeRandomBloke 0:26bfff579f01 229 // b = 0;
SomeRandomBloke 0:26bfff579f01 230 settings.maxX = 65173;
SomeRandomBloke 0:26bfff579f01 231 settings.minX = 64850;
SomeRandomBloke 0:26bfff579f01 232 settings.maxY = 490;
SomeRandomBloke 0:26bfff579f01 233 settings.minY = 141;
SomeRandomBloke 0:26bfff579f01 234 //X max 65173 min 64850, Y max 490 min 141
SomeRandomBloke 0:26bfff579f01 235 avgX=(settings.maxX+settings.minX)/2;
SomeRandomBloke 0:26bfff579f01 236 avgY=(settings.maxY+settings.minY)/2;
SomeRandomBloke 0:26bfff579f01 237 printf("avgX = %d, avgY = %d\n", avgX, avgY);
SomeRandomBloke 0:26bfff579f01 238
SomeRandomBloke 0:26bfff579f01 239 // avgX = 0;
SomeRandomBloke 0:26bfff579f01 240 // avgY = 0;
SomeRandomBloke 0:26bfff579f01 241
SomeRandomBloke 0:26bfff579f01 242 printf("calibrate\n");
SomeRandomBloke 0:26bfff579f01 243 calXY();
SomeRandomBloke 0:26bfff579f01 244 printf("....Finished\n");
SomeRandomBloke 0:26bfff579f01 245 printf("avgX = %d, avgY = %d\n", avgX, avgY);
SomeRandomBloke 0:26bfff579f01 246
SomeRandomBloke 0:26bfff579f01 247 // greenLed = 1;
SomeRandomBloke 0:26bfff579f01 248 redLed = 1;
SomeRandomBloke 0:26bfff579f01 249 greenLed = 1;
SomeRandomBloke 0:26bfff579f01 250 blueLed = 1;
SomeRandomBloke 0:26bfff579f01 251
SomeRandomBloke 0:26bfff579f01 252 while (1) {
SomeRandomBloke 0:26bfff579f01 253 wait(0.5);
SomeRandomBloke 0:26bfff579f01 254 int xVal = readVal(MAG_OUT_X_MSB);
SomeRandomBloke 0:26bfff579f01 255 int yVal = readVal(MAG_OUT_Y_MSB);
SomeRandomBloke 0:26bfff579f01 256 float heading = (atan2((double)(yVal-avgY),(double)(xVal-avgX)))*180/PI;
SomeRandomBloke 0:26bfff579f01 257 // float heading = (atan2((double)(xVal-avgX),(double)(yVal-avgY)))*180/PI;
SomeRandomBloke 0:26bfff579f01 258
SomeRandomBloke 0:26bfff579f01 259 if (abs(heading) <= 22.5) { printf("N\n"); greenLed = 0; } else greenLed = 1;
SomeRandomBloke 0:26bfff579f01 260 if (abs(heading) >= 157.5) printf("S\n");
SomeRandomBloke 0:26bfff579f01 261 if (heading >= 67.5 && heading <= 112.5) printf("E \n");
SomeRandomBloke 0:26bfff579f01 262 if (heading <= -67.5 && heading >= -112.5) printf("W \n");
SomeRandomBloke 0:26bfff579f01 263 if (heading > 22.5 && heading < 67.5) printf("NE\n");
SomeRandomBloke 0:26bfff579f01 264 if (heading < -22.5 && heading > -67.5) printf("NW\n");
SomeRandomBloke 0:26bfff579f01 265 if (heading > 112.5 && heading < 157.5) printf("SE\n");
SomeRandomBloke 0:26bfff579f01 266 if (heading < -112.5 && heading > -157.5) printf("SW\n");
SomeRandomBloke 0:26bfff579f01 267
SomeRandomBloke 0:26bfff579f01 268 if (heading < 0) heading += 360.0;
SomeRandomBloke 0:26bfff579f01 269 printf("xVal - avgX = %d, yVal - avgY = %d ", xVal-avgX, yVal-avgY);
SomeRandomBloke 0:26bfff579f01 270 printf("X = %d, Y = %d, Heading %f\n", xVal, yVal, heading);
SomeRandomBloke 0:26bfff579f01 271
SomeRandomBloke 0:26bfff579f01 272
SomeRandomBloke 0:26bfff579f01 273
SomeRandomBloke 0:26bfff579f01 274 // printf("2 byte: X = %d ", readVal( 0x01 ));
SomeRandomBloke 0:26bfff579f01 275 // printf(" Y = %d ", readVal( 0x03 ));
SomeRandomBloke 0:26bfff579f01 276 // printf(" Z = %d\n", readVal( 0x05 ));
SomeRandomBloke 0:26bfff579f01 277
SomeRandomBloke 0:26bfff579f01 278 // printf("1 byte: X = %d ", readx());
SomeRandomBloke 0:26bfff579f01 279 // printf(" Y = %d ", ready());
SomeRandomBloke 0:26bfff579f01 280 // printf(" Z = %d\n", readz());
SomeRandomBloke 0:26bfff579f01 281 }
SomeRandomBloke 0:26bfff579f01 282 }