Operácie

Zbernica i2c: MCP4725: Rozdiel medzi revíziami

Z SensorWiki

(Hlavné obrázky a zdrojový kód)
Riadok 6: Riadok 6:
 
Vytvorte jednoduchý driver pre 12-bitový D/A prevodník MCP4725 s I2C zbernicou a EEPROM - zápis požadovanej hodnoty do registra a EEPROM, čítanie aktuálne nastavenej/uloženej hodnoty.
 
Vytvorte jednoduchý driver pre 12-bitový D/A prevodník MCP4725 s I2C zbernicou a EEPROM - zápis požadovanej hodnoty do registra a EEPROM, čítanie aktuálne nastavenej/uloženej hodnoty.
  
[[Obrázok:ard.jpg|400px|thumb|center|Vývojová doska ACROB.]]
+
[[Obrázok:Mcp4725_breakout.png|400px|thumb|center|12-bitový D/A prevodník MCP4725]]
  
 
'''Literatúra:'''  
 
'''Literatúra:'''  
* [http://ap.urpi.fei.stuba.sk/sensorwiki/index.php/Acrob_technical_description Dokumentácia k doske Acrob]
+
* [https://ww1.microchip.com/downloads/en/devicedoc/22039d.pdf Katalógový list čipu MCP4725]
* [http://www.humanbenchmark.com/tests/reactiontime/index.php Vyskúšajte si zmerať reakciu on-line]
+
* [https://github.com/RobTillaart/MCP4725 Arduino knižnica k MCP4725]
  
  
Riadok 17: Riadok 17:
 
== Analýza  a opis riešenia ==
 
== Analýza  a opis riešenia ==
  
Opíšte sem čo a ako ste spravili, ak treba, doplňte obrázkami...
+
[[Súbor:Mcp4725-arduino-wiring-connection.jpg|600px|thumb|center|Grafická reprezentácia pripojenia D/A prevodníka k vývojovej doske Arduino Uno]]
 
 
[[Súbor:ledRGB.jpg|400px|thumb|center|RGB LED.]]
 
  
 
Nezabudnite doplniť schému zapojenia!
 
Nezabudnite doplniť schému zapojenia!
  
[[Súbor:schd.png|400px|thumb|center|Schéma zapojenia LCD displeja.]]
+
[[Súbor:Schematic_MCP4725.png|600px|thumb|center|Schéma zapojenia D/A prevodníka MCP4725]]
  
  
Riadok 32: Riadok 30:
  
 
<tabs>
 
<tabs>
<tab name="AVR C-code"><source lang="c++" style="background: LightYellow;">
+
<tab name="MCP4725_Example.c"><source lang="c++" style="background: LightYellow;">
 +
/*
 +
* MicroProject.c
 +
*
 +
* MCP4725 I2C DAC Simple Driver Example
 +
*
 +
* Created: 6. 5. 2023 13:55:04
 +
* Author : greif
 +
*/
 +
 
 +
// Includes
 +
#include <stdio.h>
 
#include <avr/io.h>
 
#include <avr/io.h>
 +
#include "uart.h" // UART for SerialPlot output
 +
 +
#define DAC_ADDR 0x60 // MCP4725 address - if not set here, default address is 0x60
 +
#include "mcp4725.h" // MCP4725 Simple Driver
 +
 +
 +
FILE uart_stream = FDEV_SETUP_STREAM(uart_putc, uart_getc, _FDEV_SETUP_RW); // Link UART functions
 +
 +
 +
 +
// ADC initialization
 +
void adc_init(void){
 +
ADMUX = (0<<REFS1)|(1<<REFS0); // AVCC - set the ADC reference voltage
 +
ADCSRA = (1<<ADEN) // "Turn ON" the ADC
 +
|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // Set the prescaler - fOsc/128, fADC = 125kHz, conversion duration < ako 0,1ms, align right
 +
}
 +
 +
 +
 +
// Read ADC channel
 +
uint16_t adc_read(uint8_t a_pin){
 +
a_pin &= 0x07;
 +
ADMUX = (ADMUX & 0xF8)|a_pin; // Set the channel
 +
 +
ADCSRA |= (1<<ADSC); // Start the conversion
 +
while(ADCSRA & (1<<ADSC)); // Wait until conversion done
 +
 +
return (ADC);
 +
}
 +
 +
 +
  
 
int main(void)
 
int main(void)
 
{
 
{
  unsigned int measuredValue;
+
DACInit(); // Initialize the MCP4725 12b DAC on the I2C bus
 +
 +
adc_init(); // Initialize the on-board 10b ADC
 +
 +
// Initialize UART communication
 +
uart_init();
 +
stdout = stdin = &uart_stream;
 +
printf("Ready to start...\n\n");
 +
 
 +
setDACValue(2048, 1); // Write a 12b (0-4095) value to DAC register and EEPROM
 +
 +
// Gradually increase MCP4725 output, while displaying measured voltage (ADC reading) and MCP4725 register/EEPROM readings
 +
uint16_t i = 0;
 +
    while (1)
 +
    {
 +
uint16_t adcValue = adc_read(0); // Get ADC reading from the MCP4725 output pin
 +
uint16_t eeprom = readEEPROM(); // Read current EEPROM value from MCP4725 (persistent)
 +
uint16_t current = readDACValue(); // Read current DAC register value from MCP_4725 (temporary)
 +
 +
// Reset counter if out of MCP4725 12b range
 +
if(i > DAC_MAX){
 +
i = DAC_MIN;
 +
}
 +
 +
setDACValue(i, 0); // Write a 12b (0-4095) value to DAC register - without writing the EEPROM
 +
i+=10; // Increase the counter
 +
 +
printf("%u %u %u\r\n", adcValue, eeprom, current); // Send measured values to UART (SerialPlot)
 +
    }
 +
 +
return 0;
 +
}
 +
 
 +
 
 +
</source></tab>
 +
<tab name="mcp4725.c"><source lang="c++" style="background: LightYellow;">
 +
/*
 +
* mcp4725.c
 +
*
 +
* Simple MCP725 12b I2C DAC Driver
 +
*
 +
* Created: 5. 6. 2023 10:51:34
 +
*  Author: greif
 +
*/
 +
 
 +
#include "mcp4725.h"
 +
#include "i2cmaster.h" // Standard I2C library
 +
 
 +
 
 +
 
 +
#define DAC_REG_WRITE 0x40 // Write mode - DAC register only, EEPROM unchanged
 +
#define DAC_EEPROM_REG_WRITE 0x60 // // Write mode - both DAC register and EEPROM
 +
#define DAC_RESET 0x06 // MCP4725 reset command (general call)
 +
 
 +
 
 +
 
 +
// Perform internal MCP4725 reset - EEPROM data uploaded to the DAC register
 +
void resetDAC(){
 +
i2c_start_wait( (DAC_ADDR << 1) | I2C_WRITE); // Start I2C communication with MCP4725 (ack polling), write mode
 +
i2c_write(0x00); // Start address 0x00 (I2C general call)
 +
i2c_write(DAC_RESET); // Send reset command
 +
i2c_stop(); // Stop I2C communication
 +
}
 +
 
 +
 
 +
 
 +
// Initialize MCP4725
 +
void DACInit(){
 +
i2c_init(); // initialize the I2C library
 +
resetDAC(); // Issue a general call reset after power-on (recommended by manufacturer - in case the automatic power-on reset did not work)
 +
}
 +
 
 +
 
 +
 
 +
/* Write MCP4725 register
 +
*
 +
* Parameters:
 +
* const uint16_t value - 12b value representing output voltage
 +
* const int EEPROM - write mode:
 +
* if true, value is written to both DAC register and EEPROM - slow
 +
* if false, value is written only to the DAC register - fast
 +
*/
 +
void writeDAC(const uint16_t value, const int EEPROM){
 +
i2c_start_wait( (DAC_ADDR << 1) | I2C_WRITE); // Start I2C communication with MCP4725 (ack polling), write mode
 +
i2c_write(EEPROM ? DAC_EEPROM_REG_WRITE : DAC_REG_WRITE); // Set write address depending on write mode (parameter)
 +
i2c_write((value & 0xFF0) >> 4); // Write upper data bits (D11, D10, D9, D8, D7, D6, D5, D4)
 +
i2c_write((value & 0xF) << 4); // Write Lower data bits (D3, D2, D1, D0)
 +
i2c_stop(); // Stop I2C communication
 +
}
 +
 
 +
 
 +
 
 +
/* Read MCP4725 register
 +
*
 +
* Parameters:
 +
* uint8_t *buffer - buffer pointer to store read bits
 +
* const uint8_t length - buffer length
 +
*/
 +
void readDACRegister(uint8_t *buffer, const uint8_t length){
 +
i2c_start_wait( (DAC_ADDR << 1) | I2C_WRITE); // Start I2C communication with MCP4725 (ack polling), write mode
 +
i2c_write(0x00); // Set the address to the start (0x00)
 +
 +
i2c_rep_start( (DAC_ADDR << 1) | I2C_READ ); // Start I2C communication with MCP4725 again, this time in read mode
 +
 +
// Read (length-1) bits from the register
 +
uint8_t counter = 0;
 +
while (counter < length-1){
 +
buffer[counter++] = i2c_readAck(); // Read the bit, continue requesting data
 +
}
 +
buffer[counter] = i2c_readNak(); // Read the last wanted bit, do not request any other data
 +
 +
i2c_stop(); // Stop I2C communication
 +
}
 +
 
 +
 
 +
 
 +
// Check if writing to the EEPROM has finished
 +
int DACReady(){
 +
uint8_t buffer[1];
 +
readDACRegister(buffer, 1); // Read the first byte
 +
return ((buffer[0] & 0x80) > 0); // Return the status of the first bit
 +
}
 +
 
 +
 
 +
 
 +
// Read the set value form MCP4725 EEPROM
 +
uint16_t readEEPROM(){
 +
while(!DACReady()); // Wait until writing to the EEPROM is finished
 +
 +
uint8_t buffer[5];
 +
readDACRegister(buffer, 5); // Read 5 bytes (EEPROM data in the 4-5th byte)
 +
 +
// Convert read bytes to the actual set 12b value
 +
uint16_t result = buffer[3] & 0x0F;
 +
result = result << 8;
 +
result = result + buffer[4];
 +
 +
return result;
 +
}
 +
 
 +
 
 +
 
 +
// Read the set value from MCP4725 DAC register
 +
uint16_t readDACValue(){
 +
while(!DACReady()); // Wait until writing to the EEPROM is finished
 +
 +
uint8_t buffer[3];
 +
readDACRegister(buffer, 3); // Read 3 bytes (DAC data in the 2-3th byte)
 +
 +
// Convert read bytes to the actual set 12b value
 +
uint16_t result = buffer[1];
 +
result = result << 4;
 +
result = result + (buffer[2] >> 4);
 +
 +
return result;
 +
}
 +
 
  
  while (1)
 
  {
 
    /*  relax  */ 
 
  }
 
  
  return(0);
+
/* Set MCP4725 value
 +
* Wrapper of void writeDAC(const uint16_t value, const int EEPROM)
 +
* Added input range check
 +
*
 +
* Parameters:
 +
* const uint16_t value - 12b value representing output voltage
 +
* const int persistent - write mode:
 +
* if true, value is written to both DAC register and EEPROM - slow, value stays unchanged after reset
 +
* if false, value is written only to the DAC register - fast, value changes after reset - to the EEPROM value
 +
*
 +
* Return:
 +
* 1 if value out of range
 +
* 0 if write successful
 +
*/
 +
int setDACValue(uint16_t value, const int persistent){
 +
// Check the input range
 +
if(value < DAC_MIN || value > DAC_MAX){
 +
return 1;
 +
}
 +
 +
while(!DACReady()); // Wait until writing to the EEPROM is finished
 +
writeDAC(value, persistent); // Depending on the write mode, write the value to MCP4725
 +
 +
return 0;
 
}
 
}
 +
</source></tab>
 +
<tab name="mcp4725.h"><source lang="c++" style="background: LightYellow;">
 +
/*
 +
* mcp4725.h
 +
*
 +
* Simple MCP725 12b I2C DAC Driver
 +
*
 +
* Created: 5. 6. 2023 10:52:00
 +
*  Author: greif
 +
*/
 +
 +
 +
#ifndef MCP4725_H_
 +
#define MCP4725_H_
 +
 +
#include <stdio.h>
 +
 +
 +
#ifndef F_CPU
 +
#define F_CPU 16000000UL
 +
#endif
 +
 +
// If not defined otherwise, set the MCP4725 address to 0x60
 +
#ifndef DAC_ADDR
 +
#define DAC_ADDR 0x60
 +
#endif
 +
 +
 +
// Define MCP4725 range (12b)
 +
#define DAC_MIN 0
 +
#define DAC_MAX 4095
 +
 +
 +
void resetDAC();
 +
void DACInit();
 +
void writeDAC(const uint16_t value, const int EEPROM);
 +
void readDACRegister(uint8_t *buffer, const uint8_t length);
 +
int DACReady();
 +
uint16_t readEEPROM();
 +
uint16_t readDACValue();
 +
int setDACValue(uint16_t value, const int persistent);
 +
  
 +
#endif /* MCP4725_H_ */
 
</source></tab>
 
</source></tab>
<tab name="filename.h"><source lang="c++" style="background: LightYellow;">
+
<tab name="uart.c"><source lang="c++" style="background: LightYellow;">
 +
#include "uart.h"
 
#include <avr/io.h>
 
#include <avr/io.h>
 +
#include <util/setbaud.h>
 +
 +
 +
 +
void uart_init( void )
 +
{
 +
UBRR0H = UBRRH_VALUE;
 +
UBRR0L = UBRRL_VALUE;
 +
 +
#if USE_2X
 +
UCSR0A |= _BV(U2X0);
 +
#else
 +
UCSR0A &= ~(_BV(U2X0));
 +
#endif
 +
 +
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
 +
UCSR0B = _BV(RXEN0) | _BV(TXEN0);  /* Enable RX and TX */
 +
}
 +
 +
 +
void uart_putc(char c)
 +
{
 +
if (c == '\n')
 +
{
 +
uart_putc('\r');
 +
}
 +
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
 +
UDR0 = c;
 +
}
 +
 +
 +
void uart_puts(const char *s)
 +
{
 +
/* toto je vasa uloha */
 +
int i = 0;
 +
while(s[i] != '\0'){
 +
uart_putc(s[i]);
 +
i++;
 +
}
 +
}
 +
 +
char uart_getc(void) {
 +
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
 +
return UDR0;
 +
}
 +
</source></tab>
 +
<tab name="uart.h"><source lang="c++" style="background: LightYellow;">
 +
/* ************************************************************************* */
 +
/* FileName          : uart.h                                              */
 +
/* ************************************************************************* */
 +
 +
#ifndef F_CPU
 +
#define F_CPU 16000000UL
 +
#endif
 +
 +
#define BAUD 9600
 +
 +
void uart_init( void );
 +
 +
void uart_putc( char c );
 +
void uart_puts( const char *s );
 +
 +
char uart_getc( void );
 +
</source></tab>
 +
<tab name="i2cmaster.c"><source lang="c++" style="background: LightYellow;">
 +
 +
/*************************************************************************
 +
* Title:    I2C master library using hardware TWI interface
 +
* Author:  Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
 +
* File:    $Id: twimaster.c,v 1.4 2015/01/17 12:16:05 peter Exp $
 +
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
 +
* Target:  any AVR device with hardware TWI
 +
* Usage:    API compatible with I2C Software Library i2cmaster.h
 +
**************************************************************************/
 +
#include <inttypes.h>
 +
#include <compat/twi.h>
 +
 +
#include "i2cmaster.h"
 +
 +
 +
/* define CPU frequency in hz here if not defined in Makefile */
 +
#ifndef F_CPU
 +
#define F_CPU 16000000UL
 +
#endif
 +
 +
/* I2C clock in Hz */
 +
#define SCL_CLOCK  100000L
 +
 +
 +
/*************************************************************************
 +
Initialization of the I2C bus interface. Need to be called only once
 +
*************************************************************************/
 +
void i2c_init(void)
 +
{
 +
  /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
 +
 
 +
  TWSR = 0;                        /* no prescaler */
 +
  TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */
 +
 +
}/* i2c_init */
 +
 +
 +
/*************************************************************************
 +
  Issues a start condition and sends address and transfer direction.
 +
  return 0 = device accessible, 1= failed to access device
 +
*************************************************************************/
 +
unsigned char i2c_start(unsigned char address)
 +
{
 +
    uint8_t  twst;
 +
 +
// send START condition
 +
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
 +
 +
// wait until transmission completed
 +
while(!(TWCR & (1<<TWINT)));
 +
 +
// check value of TWI Status Register. Mask prescaler bits.
 +
twst = TW_STATUS & 0xF8;
 +
if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;
 +
 +
// send device address
 +
TWDR = address;
 +
TWCR = (1<<TWINT) | (1<<TWEN);
 +
 +
// wail until transmission completed and ACK/NACK has been received
 +
while(!(TWCR & (1<<TWINT)));
 +
 +
// check value of TWI Status Register. Mask prescaler bits.
 +
twst = TW_STATUS & 0xF8;
 +
if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;
 +
 +
return 0;
 +
 +
}/* i2c_start */
 +
 +
 +
/*************************************************************************
 +
Issues a start condition and sends address and transfer direction.
 +
If device is busy, use ack polling to wait until device is ready
 +
 +
Input:  address and transfer direction of I2C device
 +
*************************************************************************/
 +
void i2c_start_wait(unsigned char address)
 +
{
 +
    uint8_t  twst;
 +
 +
 +
    while ( 1 )
 +
    {
 +
    // send START condition
 +
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
 +
   
 +
    // wait until transmission completed
 +
    while(!(TWCR & (1<<TWINT)));
 +
   
 +
    // check value of TWI Status Register. Mask prescaler bits.
 +
    twst = TW_STATUS & 0xF8;
 +
    if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
 +
   
 +
    // send device address
 +
    TWDR = address;
 +
    TWCR = (1<<TWINT) | (1<<TWEN);
 +
   
 +
    // wail until transmission completed
 +
    while(!(TWCR & (1<<TWINT)));
 +
   
 +
    // check value of TWI Status Register. Mask prescaler bits.
 +
    twst = TW_STATUS & 0xF8;
 +
    if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) )
 +
    {       
 +
        /* device busy, send stop condition to terminate write operation */
 +
        TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
 +
       
 +
        // wait until stop condition is executed and bus released
 +
        while(TWCR & (1<<TWSTO));
 +
       
 +
        continue;
 +
    }
 +
    //if( twst != TW_MT_SLA_ACK) return 1;
 +
    break;
 +
    }
 +
 +
}/* i2c_start_wait */
 +
 +
 +
/*************************************************************************
 +
Issues a repeated start condition and sends address and transfer direction
 +
 +
Input:  address and transfer direction of I2C device
 +
 +
Return:  0 device accessible
 +
          1 failed to access device
 +
*************************************************************************/
 +
unsigned char i2c_rep_start(unsigned char address)
 +
{
 +
    return i2c_start( address );
 +
 +
}/* i2c_rep_start */
 +
 +
 +
/*************************************************************************
 +
Terminates the data transfer and releases the I2C bus
 +
*************************************************************************/
 +
void i2c_stop(void)
 +
{
 +
    /* send stop condition */
 +
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
 +
 +
// wait until stop condition is executed and bus released
 +
while(TWCR & (1<<TWSTO));
 +
 +
}/* i2c_stop */
 +
 +
 +
/*************************************************************************
 +
  Send one byte to I2C device
 +
 
 +
  Input:    byte to be transfered
 +
  Return:  0 write successful
 +
            1 write failed
 +
*************************************************************************/
 +
unsigned char i2c_write( unsigned char data )
 +
{
 +
    uint8_t  twst;
 +
   
 +
// send data to the previously addressed device
 +
TWDR = data;
 +
TWCR = (1<<TWINT) | (1<<TWEN);
 +
 +
// wait until transmission completed
 +
while(!(TWCR & (1<<TWINT)));
 +
 +
// check value of TWI Status Register. Mask prescaler bits
 +
twst = TW_STATUS & 0xF8;
 +
if( twst != TW_MT_DATA_ACK) return 1;
 +
return 0;
 +
 +
}/* i2c_write */
 +
 +
 +
/*************************************************************************
 +
Read one byte from the I2C device, request more data from device
 +
 +
Return:  byte read from I2C device
 +
*************************************************************************/
 +
unsigned char i2c_readAck(void)
 +
{
 +
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
 +
while(!(TWCR & (1<<TWINT)));   
 +
 +
    return TWDR;
 +
 +
}/* i2c_readAck */
 +
 +
 +
/*************************************************************************
 +
Read one byte from the I2C device, read is followed by a stop condition
 +
 +
Return:  byte read from I2C device
 +
*************************************************************************/
 +
unsigned char i2c_readNak(void)
 +
{
 +
TWCR = (1<<TWINT) | (1<<TWEN);
 +
while(!(TWCR & (1<<TWINT)));
 +
 +
    return TWDR;
 +
 +
}/* i2c_readNak */
 +
</source></tab>
 +
<tab name="i2cmaster.h"><source lang="c++" style="background: LightYellow;">
 +
 +
#ifndef I2CMASTER_H_
 +
#define I2CMASTER_H_
 +
 +
 +
#ifndef _I2CMASTER_H
 +
#define _I2CMASTER_H
 +
/*************************************************************************
 +
* Title:    C include file for the I2C master interface
 +
*          (i2cmaster.S or twimaster.c)
 +
* Author:  Peter Fleury <pfleury@gmx.ch>
 +
* File:    $Id: i2cmaster.h,v 1.12 2015/09/16 09:27:58 peter Exp $
 +
* Software: AVR-GCC 4.x
 +
* Target:  any AVR device
 +
* Usage:    see Doxygen manual
 +
**************************************************************************/
 +
 +
/**
 +
@file
 +
@defgroup pfleury_ic2master I2C Master library
 +
@code #include <i2cmaster.h> @endcode
 +
 
 +
@brief I2C (TWI) Master Software Library
 +
 +
Basic routines for communicating with I2C slave devices. This single master
 +
implementation is limited to one bus master on the I2C bus.
 +
 +
This I2c library is implemented as a compact assembler software implementation of the I2C protocol
 +
which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).
 +
Since the API for these two implementations is exactly the same, an application can be linked either against the
 +
software I2C implementation or the hardware I2C implementation.
 +
 +
Use 4.7k pull-up resistor on the SDA and SCL pin.
 +
 +
Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module
 +
i2cmaster.S to your target when using the software I2C implementation !
 +
 +
Adjust the  CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.
 +
 +
@note
 +
    The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted
 +
    to GNU assembler and AVR-GCC C call interface.
 +
    Replaced the incorrect quarter period delays found in AVR300 with
 +
    half period delays.
 +
   
 +
@author Peter Fleury pfleury@gmx.ch  http://tinyurl.com/peterfleury
 +
@copyright (C) 2015 Peter Fleury, GNU General Public License Version 3
 +
 +
@par API Usage Example
 +
  The following code shows typical usage of this library, see example test_i2cmaster.c
 +
 +
@code
 +
 +
#include <i2cmaster.h>
 +
 +
 +
#define Dev24C02  0xA2      // device address of EEPROM 24C02, see datasheet
 +
 +
int main(void)
 +
{
 +
    unsigned char ret;
 +
 +
    i2c_init();                            // initialize I2C library
 +
 +
    // write 0x75 to EEPROM address 5 (Byte Write)
 +
    i2c_start_wait(Dev24C02+I2C_WRITE);    // set device address and write mode
 +
    i2c_write(0x05);                        // write address = 5
 +
    i2c_write(0x75);                        // write value 0x75 to EEPROM
 +
    i2c_stop();                            // set stop conditon = release bus
 +
 +
 +
    // read previously written value back from EEPROM address 5
 +
    i2c_start_wait(Dev24C02+I2C_WRITE);    // set device address and write mode
 +
 +
    i2c_write(0x05);                        // write address = 5
 +
    i2c_rep_start(Dev24C02+I2C_READ);      // set device address and read mode
 +
 +
    ret = i2c_readNak();                    // read one byte from EEPROM
 +
    i2c_stop();
 +
 +
    for(;;);
 +
}
 +
@endcode
 +
 +
*/
 +
 +
 +
/**@{*/
 +
 +
#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
 +
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
 +
#endif
 +
 +
#include <avr/io.h>
 +
 +
/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
 +
#define I2C_READ    1
 +
 +
/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
 +
#define I2C_WRITE  0
 +
 +
 +
/**
 +
@brief initialize the I2C master interace. Need to be called only once
 +
@return none
 +
*/
 +
extern void i2c_init(void);
 +
 +
 +
/**
 +
@brief Terminates the data transfer and releases the I2C bus
 +
@return none
 +
*/
 +
extern void i2c_stop(void);
 +
 +
 +
/**
 +
@brief Issues a start condition and sends address and transfer direction
 +
 
 +
@param    addr address and transfer direction of I2C device
 +
@retval  0  device accessible
 +
@retval  1  failed to access device
 +
*/
 +
extern unsigned char i2c_start(unsigned char addr);
 +
 +
 +
/**
 +
@brief Issues a repeated start condition and sends address and transfer direction
 +
 +
@param  addr address and transfer direction of I2C device
 +
@retval  0 device accessible
 +
@retval  1 failed to access device
 +
*/
 +
extern unsigned char i2c_rep_start(unsigned char addr);
 +
 +
 +
/**
 +
@brief Issues a start condition and sends address and transfer direction
 +
 
 +
If device is busy, use ack polling to wait until device ready
 +
@param    addr address and transfer direction of I2C device
 +
@return  none
 +
*/
 +
extern void i2c_start_wait(unsigned char addr);
 +
 +
 +
/**
 +
@brief Send one byte to I2C device
 +
@param    data  byte to be transfered
 +
@retval  0 write successful
 +
@retval  1 write failed
 +
*/
 +
extern unsigned char i2c_write(unsigned char data);
 +
 +
 +
/**
 +
@brief    read one byte from the I2C device, request more data from device
 +
@return  byte read from I2C device
 +
*/
 +
extern unsigned char i2c_readAck(void);
 +
 +
/**
 +
@brief    read one byte from the I2C device, read is followed by a stop condition
 +
@return  byte read from I2C device
 +
*/
 +
extern unsigned char i2c_readNak(void);
 +
 +
/**
 +
@brief    read one byte from the I2C device
 +
 +
Implemented as a macro, which calls either @ref i2c_readAck or @ref i2c_readNak
 +
 +
@param    ack 1 send ack, request more data from device<br>
 +
              0 send nak, read is followed by a stop condition
 +
@return  byte read from I2C device
 +
*/
 +
extern unsigned char i2c_read(unsigned char ack);
 +
#define i2c_read(ack)  (ack) ? i2c_readAck() : i2c_readNak();
 +
 +
 +
 +
/**@}*/
 +
#endif
  
void adc_init(void);                                  // A/D converter initialization
 
  
unsigned int adc_read(char a_pin);
+
#endif /* I2CMASTER_H_ */
 
</source></tab>
 
</source></tab>
 
</tabs>
 
</tabs>
Riadok 59: Riadok 771:
 
Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'':  
 
Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'':  
  
Zdrojový kód: [[Médiá:projektMenoPriezvisko.zip|zdrojaky.zip]]
+
Zdrojový kód: [[Médiá:MCP4725_source_code.zip |MCP4725_Source.zip]]
  
  

Verzia zo dňa a času 10:17, 7. jún 2023

Záverečný projekt predmetu MIPS / LS2023 - Kristián Greif


Zadanie

Vytvorte jednoduchý driver pre 12-bitový D/A prevodník MCP4725 s I2C zbernicou a EEPROM - zápis požadovanej hodnoty do registra a EEPROM, čítanie aktuálne nastavenej/uloženej hodnoty.

12-bitový D/A prevodník MCP4725

Literatúra:


Analýza a opis riešenia

Grafická reprezentácia pripojenia D/A prevodníka k vývojovej doske Arduino Uno

Nezabudnite doplniť schému zapojenia!

Schéma zapojenia D/A prevodníka MCP4725


Algoritmus a program

Algoritmus programu je....


/*
 * MicroProject.c
 * 
 * MCP4725 I2C DAC Simple Driver Example
 *
 * Created: 6. 5. 2023 13:55:04
 * Author : greif
 */ 

// Includes
#include <stdio.h>
#include <avr/io.h>
#include "uart.h" // UART for SerialPlot output

#define DAC_ADDR 0x60 // MCP4725 address - if not set here, default address is 0x60
#include "mcp4725.h" // MCP4725 Simple Driver


FILE uart_stream = FDEV_SETUP_STREAM(uart_putc, uart_getc, _FDEV_SETUP_RW); // Link UART functions



// ADC initialization
void adc_init(void){
	ADMUX = (0<<REFS1)|(1<<REFS0); // AVCC - set the ADC reference voltage
	ADCSRA = (1<<ADEN) // "Turn ON" the ADC
	|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); // Set the prescaler - fOsc/128, fADC = 125kHz, conversion duration < ako 0,1ms, align right
}



// Read ADC channel
uint16_t adc_read(uint8_t a_pin){
	a_pin &= 0x07;
	ADMUX = (ADMUX & 0xF8)|a_pin; // Set the channel
	
	ADCSRA |= (1<<ADSC); // Start the conversion
	while(ADCSRA & (1<<ADSC)); // Wait until conversion done
	
	return (ADC);
}




int main(void)
{
	DACInit(); // Initialize the MCP4725 12b DAC on the I2C bus
	
	adc_init(); // Initialize the on-board 10b ADC
	
	// Initialize UART communication
	uart_init();
	stdout = stdin = &uart_stream;
	printf("Ready to start...\n\n");

	setDACValue(2048, 1); // Write a 12b (0-4095) value to DAC register and EEPROM
	
	// Gradually increase MCP4725 output, while displaying measured voltage (ADC reading) and MCP4725 register/EEPROM readings
	uint16_t i = 0;
    while (1) 
    {
		uint16_t adcValue = adc_read(0); // Get ADC reading from the MCP4725 output pin
		uint16_t eeprom = readEEPROM(); // Read current EEPROM value from MCP4725 (persistent)
		uint16_t current = readDACValue(); // Read current DAC register value from MCP_4725 (temporary)
		
		// Reset counter if out of MCP4725 12b range
 		if(i > DAC_MAX){
			 i = DAC_MIN;
		}
		
		setDACValue(i, 0); // Write a 12b (0-4095) value to DAC register - without writing the EEPROM
		i+=10; // Increase the counter
		
		printf("%u %u %u\r\n", adcValue, eeprom, current); // Send measured values to UART (SerialPlot)
    }
	
	return 0;
}
/*
 * mcp4725.c
 *
 * Simple MCP725 12b I2C DAC Driver
 *
 * Created: 5. 6. 2023 10:51:34
 *  Author: greif
 */ 

#include "mcp4725.h"
#include "i2cmaster.h" // Standard I2C library



#define DAC_REG_WRITE 0x40 // Write mode - DAC register only, EEPROM unchanged
#define DAC_EEPROM_REG_WRITE 0x60 // // Write mode - both DAC register and EEPROM
#define DAC_RESET 0x06 // MCP4725 reset command (general call)



// Perform internal MCP4725 reset - EEPROM data uploaded to the DAC register
void resetDAC(){
	i2c_start_wait( (DAC_ADDR << 1) | I2C_WRITE); // Start I2C communication with MCP4725 (ack polling), write mode
	i2c_write(0x00); // Start address 0x00 (I2C general call)
	i2c_write(DAC_RESET); // Send reset command
	i2c_stop(); // Stop I2C communication
}



// Initialize MCP4725
void DACInit(){
	i2c_init(); // initialize the I2C library
	resetDAC(); // Issue a general call reset after power-on (recommended by manufacturer - in case the automatic power-on reset did not work)
}



/* Write MCP4725 register
*
* Parameters: 
*	const uint16_t value - 12b value representing output voltage
*	const int EEPROM - write mode:
*		if true, value is written to both DAC register and EEPROM - slow
*		if false, value is written only to the DAC register - fast
*/
void writeDAC(const uint16_t value, const int EEPROM){
	i2c_start_wait( (DAC_ADDR << 1) | I2C_WRITE); // Start I2C communication with MCP4725 (ack polling), write mode
	i2c_write(EEPROM ? DAC_EEPROM_REG_WRITE : DAC_REG_WRITE); // Set write address depending on write mode (parameter)
	i2c_write((value & 0xFF0) >> 4); // Write upper data bits (D11, D10, D9, D8, D7, D6, D5, D4)
	i2c_write((value & 0xF) << 4); // Write Lower data bits (D3, D2, D1, D0)
	i2c_stop(); // Stop I2C communication
}



/* Read MCP4725 register
*
* Parameters:
*	uint8_t *buffer - buffer pointer to store read bits
*	const uint8_t length - buffer length
*/
void readDACRegister(uint8_t *buffer, const uint8_t length){
	i2c_start_wait( (DAC_ADDR << 1) | I2C_WRITE); // Start I2C communication with MCP4725 (ack polling), write mode
	i2c_write(0x00); // Set the address to the start (0x00)
	
	i2c_rep_start( (DAC_ADDR << 1) | I2C_READ ); // Start I2C communication with MCP4725 again, this time in read mode
	
	// Read (length-1) bits from the register
	uint8_t counter = 0;
	while (counter < length-1){
		buffer[counter++] = i2c_readAck(); // Read the bit, continue requesting data
	}
	buffer[counter] = i2c_readNak(); // Read the last wanted bit, do not request any other data
	
	i2c_stop(); // Stop I2C communication
}



// Check if writing to the EEPROM has finished
int DACReady(){
	uint8_t buffer[1];
	readDACRegister(buffer, 1); // Read the first byte
	return ((buffer[0] & 0x80) > 0); // Return the status of the first bit
}



// Read the set value form MCP4725 EEPROM
uint16_t readEEPROM(){
	while(!DACReady()); // Wait until writing to the EEPROM is finished
	
	uint8_t buffer[5];
	readDACRegister(buffer, 5); // Read 5 bytes (EEPROM data in the 4-5th byte)
	
	// Convert read bytes to the actual set 12b value
	uint16_t result = buffer[3] & 0x0F;
	result = result << 8;
	result = result + buffer[4];
	
	return result;
}



// Read the set value from MCP4725 DAC register
uint16_t readDACValue(){
	while(!DACReady()); // Wait until writing to the EEPROM is finished
	
	uint8_t buffer[3];
	readDACRegister(buffer, 3); // Read 3 bytes (DAC data in the 2-3th byte)
	
	// Convert read bytes to the actual set 12b value
	uint16_t result = buffer[1];
	result = result << 4;
	result = result + (buffer[2] >> 4);
	
	return result;
}



/* Set MCP4725 value
* Wrapper of void writeDAC(const uint16_t value, const int EEPROM)
* Added input range check
*
* Parameters:
*	const uint16_t value - 12b value representing output voltage
*	const int persistent - write mode:
*		if true, value is written to both DAC register and EEPROM - slow, value stays unchanged after reset
*		if false, value is written only to the DAC register - fast, value changes after reset - to the EEPROM value
*
* Return:
*	1 if value out of range
*	0 if write successful
*/
int setDACValue(uint16_t value, const int persistent){
	// Check the input range
	if(value < DAC_MIN || value > DAC_MAX){
		return 1;
	}
	
	while(!DACReady()); // Wait until writing to the EEPROM is finished
	writeDAC(value, persistent); // Depending on the write mode, write the value to MCP4725
	
	return 0;
}
/*
 * mcp4725.h
 *
 * Simple MCP725 12b I2C DAC Driver
 *
 * Created: 5. 6. 2023 10:52:00
 *  Author: greif
 */ 


#ifndef MCP4725_H_
#define MCP4725_H_

#include <stdio.h>


#ifndef F_CPU
#define F_CPU 16000000UL
#endif

// If not defined otherwise, set the MCP4725 address to 0x60
#ifndef DAC_ADDR
#define DAC_ADDR 0x60
#endif


// Define MCP4725 range (12b)
#define DAC_MIN 0
#define DAC_MAX 4095


void resetDAC();
void DACInit();
void writeDAC(const uint16_t value, const int EEPROM);
void readDACRegister(uint8_t *buffer, const uint8_t length);
int DACReady();
uint16_t readEEPROM();
uint16_t readDACValue();
int setDACValue(uint16_t value, const int persistent);


#endif /* MCP4725_H_ */
#include "uart.h"
#include <avr/io.h>
#include <util/setbaud.h>



void uart_init( void )
{
	UBRR0H = UBRRH_VALUE;
	UBRR0L = UBRRL_VALUE;

	#if USE_2X
	UCSR0A |= _BV(U2X0);
	#else
	UCSR0A &= ~(_BV(U2X0));
	#endif

	UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
	UCSR0B = _BV(RXEN0) | _BV(TXEN0);   /* Enable RX and TX */
}


void uart_putc(char c)
{
	if (c == '\n')
	{
		uart_putc('\r');
	}
	loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
	UDR0 = c;
}


void uart_puts(const char *s)
{
	/* toto je vasa uloha */
	int i = 0;
	while(s[i] != '\0'){
		uart_putc(s[i]);
		i++;
	}
}

char uart_getc(void) {
	loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
	return UDR0;
}
/* ************************************************************************* */
/* FileName          : uart.h                                              */
/* ************************************************************************* */

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

#define BAUD 9600

void uart_init( void );

void uart_putc( char c );
void uart_puts( const char *s );

char uart_getc( void );
/*************************************************************************
* Title:    I2C master library using hardware TWI interface
* Author:   Peter Fleury <pfleury@gmx.ch>  http://jump.to/fleury
* File:     $Id: twimaster.c,v 1.4 2015/01/17 12:16:05 peter Exp $
* Software: AVR-GCC 3.4.3 / avr-libc 1.2.3
* Target:   any AVR device with hardware TWI 
* Usage:    API compatible with I2C Software Library i2cmaster.h
**************************************************************************/
#include <inttypes.h>
#include <compat/twi.h>

#include "i2cmaster.h"


/* define CPU frequency in hz here if not defined in Makefile */
#ifndef F_CPU
#define F_CPU 16000000UL
#endif

/* I2C clock in Hz */
#define SCL_CLOCK  100000L


/*************************************************************************
 Initialization of the I2C bus interface. Need to be called only once
*************************************************************************/
void i2c_init(void)
{
  /* initialize TWI clock: 100 kHz clock, TWPS = 0 => prescaler = 1 */
  
  TWSR = 0;                         /* no prescaler */
  TWBR = ((F_CPU/SCL_CLOCK)-16)/2;  /* must be > 10 for stable operation */

}/* i2c_init */


/*************************************************************************	
  Issues a start condition and sends address and transfer direction.
  return 0 = device accessible, 1= failed to access device
*************************************************************************/
unsigned char i2c_start(unsigned char address)
{
    uint8_t   twst;

	// send START condition
	TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);

	// wait until transmission completed
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits.
	twst = TW_STATUS & 0xF8;
	if ( (twst != TW_START) && (twst != TW_REP_START)) return 1;

	// send device address
	TWDR = address;
	TWCR = (1<<TWINT) | (1<<TWEN);

	// wail until transmission completed and ACK/NACK has been received
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits.
	twst = TW_STATUS & 0xF8;
	if ( (twst != TW_MT_SLA_ACK) && (twst != TW_MR_SLA_ACK) ) return 1;

	return 0;

}/* i2c_start */


/*************************************************************************
 Issues a start condition and sends address and transfer direction.
 If device is busy, use ack polling to wait until device is ready
 
 Input:   address and transfer direction of I2C device
*************************************************************************/
void i2c_start_wait(unsigned char address)
{
    uint8_t   twst;


    while ( 1 )
    {
	    // send START condition
	    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    
    	// wait until transmission completed
    	while(!(TWCR & (1<<TWINT)));
    
    	// check value of TWI Status Register. Mask prescaler bits.
    	twst = TW_STATUS & 0xF8;
    	if ( (twst != TW_START) && (twst != TW_REP_START)) continue;
    
    	// send device address
    	TWDR = address;
    	TWCR = (1<<TWINT) | (1<<TWEN);
    
    	// wail until transmission completed
    	while(!(TWCR & (1<<TWINT)));
    
    	// check value of TWI Status Register. Mask prescaler bits.
    	twst = TW_STATUS & 0xF8;
    	if ( (twst == TW_MT_SLA_NACK )||(twst ==TW_MR_DATA_NACK) ) 
    	{    	    
    	    /* device busy, send stop condition to terminate write operation */
	        TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
	        
	        // wait until stop condition is executed and bus released
	        while(TWCR & (1<<TWSTO));
	        
    	    continue;
    	}
    	//if( twst != TW_MT_SLA_ACK) return 1;
    	break;
     }

}/* i2c_start_wait */


/*************************************************************************
 Issues a repeated start condition and sends address and transfer direction 

 Input:   address and transfer direction of I2C device
 
 Return:  0 device accessible
          1 failed to access device
*************************************************************************/
unsigned char i2c_rep_start(unsigned char address)
{
    return i2c_start( address );

}/* i2c_rep_start */


/*************************************************************************
 Terminates the data transfer and releases the I2C bus
*************************************************************************/
void i2c_stop(void)
{
    /* send stop condition */
	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWSTO);
	
	// wait until stop condition is executed and bus released
	while(TWCR & (1<<TWSTO));

}/* i2c_stop */


/*************************************************************************
  Send one byte to I2C device
  
  Input:    byte to be transfered
  Return:   0 write successful 
            1 write failed
*************************************************************************/
unsigned char i2c_write( unsigned char data )
{	
    uint8_t   twst;
    
	// send data to the previously addressed device
	TWDR = data;
	TWCR = (1<<TWINT) | (1<<TWEN);

	// wait until transmission completed
	while(!(TWCR & (1<<TWINT)));

	// check value of TWI Status Register. Mask prescaler bits
	twst = TW_STATUS & 0xF8;
	if( twst != TW_MT_DATA_ACK) return 1;
	return 0;

}/* i2c_write */


/*************************************************************************
 Read one byte from the I2C device, request more data from device 
 
 Return:  byte read from I2C device
*************************************************************************/
unsigned char i2c_readAck(void)
{
	TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA);
	while(!(TWCR & (1<<TWINT)));    

    return TWDR;

}/* i2c_readAck */


/*************************************************************************
 Read one byte from the I2C device, read is followed by a stop condition 
 
 Return:  byte read from I2C device
*************************************************************************/
unsigned char i2c_readNak(void)
{
	TWCR = (1<<TWINT) | (1<<TWEN);
	while(!(TWCR & (1<<TWINT)));
	
    return TWDR;

}/* i2c_readNak */
#ifndef I2CMASTER_H_
#define I2CMASTER_H_


#ifndef _I2CMASTER_H
#define _I2CMASTER_H
/************************************************************************* 
* Title:    C include file for the I2C master interface 
*           (i2cmaster.S or twimaster.c)
* Author:   Peter Fleury <pfleury@gmx.ch>
* File:     $Id: i2cmaster.h,v 1.12 2015/09/16 09:27:58 peter Exp $
* Software: AVR-GCC 4.x
* Target:   any AVR device
* Usage:    see Doxygen manual
**************************************************************************/

/**
 @file
 @defgroup pfleury_ic2master I2C Master library
 @code #include <i2cmaster.h> @endcode
  
 @brief I2C (TWI) Master Software Library

 Basic routines for communicating with I2C slave devices. This single master 
 implementation is limited to one bus master on the I2C bus. 

 This I2c library is implemented as a compact assembler software implementation of the I2C protocol 
 which runs on any AVR (i2cmaster.S) and as a TWI hardware interface for all AVR with built-in TWI hardware (twimaster.c).
 Since the API for these two implementations is exactly the same, an application can be linked either against the
 software I2C implementation or the hardware I2C implementation.

 Use 4.7k pull-up resistor on the SDA and SCL pin.
 
 Adapt the SCL and SDA port and pin definitions and eventually the delay routine in the module 
 i2cmaster.S to your target when using the software I2C implementation ! 
 
 Adjust the  CPU clock frequence F_CPU in twimaster.c or in the Makfile when using the TWI hardware implementaion.

 @note 
    The module i2cmaster.S is based on the Atmel Application Note AVR300, corrected and adapted 
    to GNU assembler and AVR-GCC C call interface.
    Replaced the incorrect quarter period delays found in AVR300 with 
    half period delays. 
    
 @author Peter Fleury pfleury@gmx.ch  http://tinyurl.com/peterfleury
 @copyright (C) 2015 Peter Fleury, GNU General Public License Version 3
 
 @par API Usage Example
  The following code shows typical usage of this library, see example test_i2cmaster.c

 @code

 #include <i2cmaster.h>


 #define Dev24C02  0xA2      // device address of EEPROM 24C02, see datasheet

 int main(void)
 {
     unsigned char ret;

     i2c_init();                             // initialize I2C library

     // write 0x75 to EEPROM address 5 (Byte Write) 
     i2c_start_wait(Dev24C02+I2C_WRITE);     // set device address and write mode
     i2c_write(0x05);                        // write address = 5
     i2c_write(0x75);                        // write value 0x75 to EEPROM
     i2c_stop();                             // set stop conditon = release bus


     // read previously written value back from EEPROM address 5 
     i2c_start_wait(Dev24C02+I2C_WRITE);     // set device address and write mode

     i2c_write(0x05);                        // write address = 5
     i2c_rep_start(Dev24C02+I2C_READ);       // set device address and read mode

     ret = i2c_readNak();                    // read one byte from EEPROM
     i2c_stop();

     for(;;);
 }
 @endcode

*/


/**@{*/

#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304
#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !"
#endif

#include <avr/io.h>

/** defines the data direction (reading from I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_READ    1

/** defines the data direction (writing to I2C device) in i2c_start(),i2c_rep_start() */
#define I2C_WRITE   0


/**
 @brief initialize the I2C master interace. Need to be called only once 
 @return none
 */
extern void i2c_init(void);


/** 
 @brief Terminates the data transfer and releases the I2C bus 
 @return none
 */
extern void i2c_stop(void);


/** 
 @brief Issues a start condition and sends address and transfer direction 
  
 @param    addr address and transfer direction of I2C device
 @retval   0   device accessible 
 @retval   1   failed to access device 
 */
extern unsigned char i2c_start(unsigned char addr);


/**
 @brief Issues a repeated start condition and sends address and transfer direction 

 @param   addr address and transfer direction of I2C device
 @retval  0 device accessible
 @retval  1 failed to access device
 */
extern unsigned char i2c_rep_start(unsigned char addr);


/**
 @brief Issues a start condition and sends address and transfer direction 
   
 If device is busy, use ack polling to wait until device ready 
 @param    addr address and transfer direction of I2C device
 @return   none
 */
extern void i2c_start_wait(unsigned char addr);

 
/**
 @brief Send one byte to I2C device
 @param    data  byte to be transfered
 @retval   0 write successful
 @retval   1 write failed
 */
extern unsigned char i2c_write(unsigned char data);


/**
 @brief    read one byte from the I2C device, request more data from device 
 @return   byte read from I2C device
 */
extern unsigned char i2c_readAck(void);

/**
 @brief    read one byte from the I2C device, read is followed by a stop condition 
 @return   byte read from I2C device
 */
extern unsigned char i2c_readNak(void);

/** 
 @brief    read one byte from the I2C device
 
 Implemented as a macro, which calls either @ref i2c_readAck or @ref i2c_readNak
 
 @param    ack 1 send ack, request more data from device<br>
               0 send nak, read is followed by a stop condition 
 @return   byte read from I2C device
 */
extern unsigned char i2c_read(unsigned char ack);
#define i2c_read(ack)  (ack) ? i2c_readAck() : i2c_readNak(); 



/**@}*/
#endif


#endif /* I2CMASTER_H_ */

Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x zdrojaky.zip:

Zdrojový kód: MCP4725_Source.zip


Overenie

Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia. Na konci uvádzame fotku záverečnej obrazovky pred resetom. Vypísaný je tu priemerný čas a najlepší čas.

Aplikácia.

Video:

Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.