Estoy intentando hacer lecturas a través de un ADC MAX11616 y Atmega2560 pero no he tenido éxito. Me podrían guiar en que podría estar haciendo mal.
Estoy utilizando la librería Wire.h
La dirección del MAX11616EEE+ es 0110101 (53 DEC, 0x35 HEX)
Las entradas son Single-Ended (estoy probando alimentando la entrada directamente de la salida 3.3V de arduino y GND)
De acuerdo a lo que interpreto del datasheet, he configurado el MAX11616 de la siguiente manera:
Setup Byte: 11011010 1: Selecciono escribir en Setup byte 1 0 1: Vref interna, A11/REF analog input, ref interna siempre encendida 1: reloj externo 0: unipolar 1: sin reset
Configuration Byte: 00010101 0: Selecciono escribir en Configuration byte 00 1010: escanear entradas desde A0 hasta A10 (son las entradas que estoy utilizando) 1: Selecciono modo Single-ended
Este es el código de prueba que estoy utilizando:
#include <Wire.h> //libreria para activar I2C comunicación con RTC
char c;
void setup() {
Serial1.begin(9600);// Comunicacion RS485
Wire.begin(); // join i2c bus
delay(100);
pinMode(38,OUTPUT);
digitalWrite(38,HIGH);
Wire.beginTransmission(53); //Slave addres DEC (0110101)
Wire.write(byte(218)); //Setup byte (11011010) (setup, internal reference, AREF analog input,Int. Ref always on, external clock, unipolar, sin reset, last bit dont care)
Wire.write(byte(21)); //Configuration byte (00010101) (config byte, Scan from A0 to A10, single ended)
Wire.endTransmission();
delay(50);
}
void loop() {
c = ' ';
Wire.requestFrom(53, 22); // realizo lectura
if (Wire.available()>0){
while (Wire.available()) {
c = Wire.read(); // recibo cada caracter
Serial1.print(c); // imprimo cada caracter
}}
delay(3000);
}
Nota: La salida la obtengo a través de comunicación RS485 ya que todo esta integrado en una sola tarjeta (uC ATMEGA2560, chip MAX11616EEE+, MAS485). El Max485 esta conectado a RX1 y TX1 del Atmega con su pin de control D38 para DE RE.
El diagrama de conexión es como esta en las imagenes adjuntas, las seccioné para que se puedan detallar mejor.
1.- Conexiones del Atmega256:
-Los capacitores de desacople son de 0.1uF
-Xtal 16Mhz + 2 Cap de 22pF + 1Res 1M
-2 Res Pull Up de 4,7K en el Bus I2C
2- Conexión Max11616:
-Capacitor de desacople 0.1uF
3- Entradas Max11616:
-De A0 a A10 con res Pull Down de 10k (Excepto A7)
[ltr][color=#4f4e4e] | |
+------>100nF----+-----> A7 max11616
Nota 2: La salida que obtengo es la que sigue: F000 F000 F000 F000 F000 F000 F000 F000 F000 F000 F000
Para esta respuesta tengo conectado 3.3V en el pin A0 del Max11616.
Gracias por cualquier ayuda!
[/color][/ltr]
¿Error de tipeo o error de conexión?
¿No se supone que estarías leyendo el A7 del Max que es el que no le pusiste R pulldown?
Pero dices que los 3V3 los mandas a A0...
Busqueda rápida arroja esta librería en C standard pero puedes adaptarla con suma facilidad o reforzar lo que estas haciendo.
Este es el ejemplo de uso
max11615.ino sería así mas o menos
#include "max11615.h" // include the library
/* USER CODE BEGIN 0 */
#define ADDRESS_MAX11615 0x66
MAX11615 adcDriver_1;
/* USER CODE END 0 */
void setup() {
// initialize the adcDriver_1 with the I2C handle, the I2C address \
and the settings for analog reference according to the datasheet
// analog ref: (internal) + (reference not connected) \
+ (internal reference always on)
MAX11615_Init(&adcDriver_1, &hi2c1, ADDRESS_MAX11615, 4+2+1);
Serial.begin(115200);
}
void loop(){
char buffer[40];
/* USER CODE BEGIN 2 */
uint8_t adc_value = 0;
MAX11615_ADC_Read(&adcDriver_1, 0, adc_value);
// read adc value from channel 0 and print to console
sprintf(buffer, "ADC Value CH0: %d\n", adc_value); // modificar linea si no tienes STM32 o ESP
Serial.println(buffer);
}
Que lo vuelves Arduino facilmente.
La librería quedaría asi
#include "max11615.h"
/**
* @brief writes a single value into a MAX11615 register
* @param *chip, pointer to the MAX11615 typedef struct
* @param reg, the destination register's address
* @param val, the value for the destination register
*/
uint8_t MAX11615_Write8(MAX11615 *chip, uint8_t reg, uint8_t val){
if(HAL_I2C_Mem_Write(chip->wireIface, chip->devAddress, reg, 1, &val, 1, 10) != HAL_OK)
return 1;
return 0;
}
/**
* @brief reads a single value from a MAX11615 register
* @param *chip, pointer to the MAX11615 typedef struct
* @param reg, the destination register's address
* @param val, pointer to the location where the value shall be stored
* @return 0 on success, 1 on transmission error
*/
uint8_t MAX11615_Read8(MAX11615 *chip, uint8_t reg, uint8_t *val){
if(HAL_I2C_Mem_Read(chip->wireIface, chip->devAddress, reg, 1, val, 1, 10) != HAL_OK)
return 1;
return 0;
}
/**
* @brief sets up the MAX11615 chip with the provided Vref setting
* @param *chip, pointer to the MAX11615 typedef struct
* @param *wireIface a pointer to a HAL I2C_HandleTypeDef
* @param address of the chip on the I2C bus
*/
uint8_t MAX11615_Init(MAX11615* chip, I2C_HandleTypeDef* wireIface, uint16_t address, uint8_t vRef){
chip->wireIface = wireIface;
chip->devAddress = address;
uint8_t ret = 0;
// 0 - don't care
// 1 - reset configuration register to default
// 2 - unipolar
// 3 - internal clock
// 4 - SEL0 (vRef)
// 5 - SEL1 (vRef)
// 6 - SEL2 (vRef)
vRef = (vRef<<4) & 0xf0;
vRef |= 2; // do not reset the setup register
ret += MAX11615_Setup(chip, vRef);
// 0 - Single Ended
// 1 to 4 - Channel Select: 7
// 5 to 6 - Scan Mode: read channels up to selected channel
uint8_t config_byte = 0x00;
config_byte |= 1; // single ended mode
config_byte |= ((1<<5) & (1<<6)); // SCAN bits: convert only the channel selected by CS bits
ret += MAX11615_Configuration(chip, config_byte);
return ret;
}
uint8_t MAX11615_Setup(MAX11615* chip, uint8_t data){
data = data | 0x80; // make REG bit 7 = 1 (setup byte)
if(HAL_I2C_Master_Transmit(chip->wireIface, chip->devAddress, &data, 1, 10) != HAL_OK)
return 1;
return 0;
}
uint8_t MAX11615_Configuration(MAX11615* chip, uint8_t data){
data = data & (~0x80); // make REG bit 7 = 0 (configuration byte)
if(HAL_I2C_Master_Transmit(chip->wireIface, chip->devAddress, &data, 1, 10) != HAL_OK)
return 1;
return 0;
}
/**
* Reads one channel.
* @author Miguel (5/24/2015)
* @param channel The channel to convert or read. Alternatively
* if a channel was set already leave null.
* @param val Pointer to where the return value should be stored.
* @return uint8_t
*/
uint8_t MAX11615_ADC_Read(MAX11615* chip, uint8_t channel, uint16_t* val){
uint8_t result[2] = {0,0};
uint8_t configurationByte = ( (channel<<1) & 0x0e) | 0x61;
MAX11615_Configuration(chip, configurationByte);
// the conversion consists of two bytes per channel
if(HAL_I2C_Master_Receive(chip->wireIface, chip->devAddress, &result[0], 2, 10) != HAL_OK){
return 1;
}
uint16_t value = 0;
// cast to uint16_t is necessary to not loose the values by the left shift
value = (((uint16_t)result[0] & 0x000f) << 8); // MSB is returned first
value += ((uint16_t)result[1] & 0x00ff); // read LSB
*val = value;
return 0;
}
/**
* Reads all channels conversion into a buffer/array.
*
* @author Miguel (5/24/2015)
*
* @param buffer an array where the channel read values are put.
*/
uint8_t MAX11615_Scan(MAX11615* chip, uint16_t* buffer){
uint8_t ret = 0;
uint8_t configurationByte = 0xf0;
ret += MAX11615_Configuration(chip, configurationByte);
// 2 bytes per channel. There are 8 channels
for(uint8_t i = 0;i<8;i++){
ret += MAX11615_ADC_Read(chip, i, buffer+i);
}
return ret;
}
Gatul, lo que intentaba hacer era un escaneo de todas las entradas y obtener valores solamente en A0 donde conecté los 3.3v y A7 que tiene el kty81.
Surbyte, muchas gracias. La verdad si la había visto pero aun me falta agarrar destreza por lo que no supe como trabajarla. Tomaré tus códigos y los implementaré a ver que tal me va y vuelvo para comentar los resultados!
He descargado las librerías y pegado el código que modificaste en los respectivos archivos. Las instalé y traté de correr tu programa pero me saltan errores al compilar y tengo una duda con eso.
El &hi2c1 me dice que no está declarado, leyendo la librería veo que esto hace referencia a I2C_HandleTypeDef* wireIface. Creo que es algo específico del SMT32. No sé que debería ir en su lugar para el Atmega2560.
Tampoco entiendo la suma de los números al final, entiendo que habla del Aref pero la tabla es como sigue:
Ya logré obtener lecturas del Max11616 con la librería Wire. Aparentemente era el chip defectuoso. Probé con uno nuevo y funcionó.
#include <Wire.h> //libreria para activar I2C comunicación con RTC
char c;
void setup() {
Serial1.begin(115200);// Comunicacion RS485
Wire.begin(); // join i2c bus (address optional for master)
delay(100);
pinMode(38,OUTPUT);
digitalWrite(38,HIGH);
Wire.beginTransmission(53); //Slave addres DEC (0110101)
Wire.write(0xDA); //Setup byte
Wire.write(0X21); //Configuration byte
Wire.endTransmission();
delay(50);
}
void loop() {
c = ' ';
Wire.requestFrom(53, 2); // request 6 bytes from slave device #53
while (Wire.available()) {
c = Wire.read(); // receive a byte as character
Serial1.print(c); // print the character
}
Wire.endTransmission();
delay(3000);
}
Lo hago individualmente, debo seguir trabajando un poco para el modo SCAN pero al menos ya obtengo algo.
La respuesta que obtengo al conectar 3.3v a A0 es 0000 FD00. De acuerdo al datasheet, La respuesta son 2 bytes (en esta caso FD00) donde los 4 MSB son 1 (F) y luego viene el dato. Al pasar D00 a decimal obtengo 3328. Una regla de 3 con el VRef interno (4,096) y la resolucion (4096) obtengo el valor de 3.32V.
Ahora bien, yo debería tener una resolución de 4,096/4096 = 0.001V pero al bajar 2v comienzo a perder exactitud, en aproximadamente (10mv) y al bajar aun más el rango de error se hace mayor. Mi idea era poder medir sensores que entregan valores en los rangos de 10mV hasta 2v aprox. Debería poder, podría ser problema de ruido?
Adjunto algunas imágenes de como esta hecha la tarjeta. Es de 2 capas, planos de tierra en top y bottom layer. Capacitor de desacople.
En la imagen he desactivado los planos a tierra para poder detallar de mejor manera las conexiones.