本人用的TM4C1231E6PZ芯片,最近想给程序加一个iic协议的贴电,用来储存防掉电数据。但苦于没有底层库函数,希望各位能帮帮小弟,先感谢各位了!
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
本人用的TM4C1231E6PZ芯片,最近想给程序加一个iic协议的贴电,用来储存防掉电数据。但苦于没有底层库函数,希望各位能帮帮小弟,先感谢各位了!
这个是官方的代码,操作的是AT24C08,自己修改去吧
//*****************************************************************************
//
// soft_i2c_atmel.c - Software I2C master example.
//
// Copyright (c) 2010-2014 Texas Instruments Incorporated. All rights reserved.
// Software License Agreement
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the
// distribution.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/uart.h"
#include "utils/softi2c.h"
#include "utils/uartstdio.h"
//*****************************************************************************
//
//! \addtogroup i2c_examples_list
//! <h1>SoftI2C AT24C08A EEPROM (soft_i2c_atmel)</h1>
//!
//! This example shows how to configure the SoftI2C module to read and write an
//! Atmel AT24C08A EEPROM. A pattern is written into the first 16 bytes of the
//! EEPROM and then read back.
//!
//! This example uses the following peripherals and I/O signals. You must
//! review these and change as needed for your own board:
//! - Timer0 peripheral (for the SoftI2C timer)
//! - GPIO Port B peripheral (for SoftI2C pins)
//! - PB2 (for SCL)
//! - PB3 (for SDA)
//!
//! The following UART signals are configured only for displaying console
//! messages for this example. These are not required for operation of I2C.
//! - UART0 peripheral
//! - GPIO Port A peripheral (for UART0 pins)
//! - UART0RX - PA0
//! - UART0TX - PA1
//!
//! This example uses the following interrupt handlers. To use this example
//! in your own application, you must add these interrupt handlers to your
//! vector table.
//! - INT_TIMER0A - Timer0AIntHandler
//
//*****************************************************************************
//*****************************************************************************
//
// The I2C slave address of the AT24C08A EEPROM device. This address is based
// on the A2 pin of the AT24C08A being pulled high on the board.
//
//*****************************************************************************
#define SLAVE_ADDR 0x54
//*****************************************************************************
//
// The states in the interrupt handler state machine.
//
//*****************************************************************************
#define STATE_IDLE 0
#define STATE_WRITE_NEXT 1
#define STATE_WRITE_FINAL 2
#define STATE_WAIT_ACK 3
#define STATE_SEND_ACK 4
#define STATE_READ_ONE 5
#define STATE_READ_FIRST 6
#define STATE_READ_NEXT 7
#define STATE_READ_FINAL 8
#define STATE_READ_WAIT 9
//*****************************************************************************
//
// The state of the SoftI2C module.
//
//*****************************************************************************
static tSoftI2C g_sI2C;
//*****************************************************************************
//
// The variables that track the data to be transmitted or received.
//
//*****************************************************************************
static uint8_t *g_pui8Data = 0;
static uint32_t g_ui32Count = 0;
//*****************************************************************************
//
// The current state of the interrupt handler state machine.
//
//*****************************************************************************
static volatile uint32_t g_ui32State = STATE_IDLE;
//*****************************************************************************
//
// This function sets up UART0 to be used for a console to display information
// as the example is running.
//
//*****************************************************************************
void
InitConsole(void)
{
//
// Enable GPIO port A which is used for UART0 pins.
// TODO: change this to whichever GPIO port you are using.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
//
// Configure the pin muxing for UART0 functions on port A0 and A1.
// This step is not necessary if your part does not support pin muxing.
// TODO: change this to select the port/pin you are using.
//
GPIOPinConfigure(GPIO_PA0_U0RX);
GPIOPinConfigure(GPIO_PA1_U0TX);
//
// Enable UART0 so that we can configure the clock.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
//
// Use the internal 16MHz oscillator as the UART clock source.
//
UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
//
// Select the alternate (UART) function for these pins.
// TODO: change this to select the port/pin you are using.
//
GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
//
// Initialize the UART for console I/O.
//
UARTStdioConfig(0, 115200, 16000000);
}
//*****************************************************************************
//
// The callback function for the SoftI2C module.
//
//*****************************************************************************
void
SoftI2CCallback(void)
{
//
// Clear the SoftI2C interrupt.
//
SoftI2CIntClear(&g_sI2C);
//
// Determine what to do based on the current state.
//
switch(g_ui32State)
{
//
// The idle state.
//
case STATE_IDLE:
{
//
// There is nothing to be done.
//
break;
}
//
// The state for the middle of a burst write.
//
case STATE_WRITE_NEXT:
{
//
// Write the next data byte.
//
SoftI2CDataPut(&g_sI2C, *g_pui8Data++);
g_ui32Count--;
//
// Continue the burst write.
//
SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_CONT);
//
// If there is one byte left, set the next state to the final write
// state.
//
if(g_ui32Count == 1)
{
g_ui32State = STATE_WRITE_FINAL;
}
//
// This state is done.
//
break;
}
//
// The state for the final write of a burst sequence.
//
case STATE_WRITE_FINAL:
{
//
// Write the final data byte.
//
SoftI2CDataPut(&g_sI2C, *g_pui8Data++);
g_ui32Count--;
//
// Finish the burst write.
//
SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_FINISH);
//
// The next state is to wait for the burst write to complete.
//
g_ui32State = STATE_SEND_ACK;
//
// This state is done.
//
break;
}
//
// Wait for an ACK on the read after a write.
//
case STATE_WAIT_ACK:
{
//
// See if there was an error on the previously issued read.
//
if(SoftI2CErr(&g_sI2C) == SOFTI2C_ERR_NONE)
{
//
// Read the byte received.
//
SoftI2CDataGet(&g_sI2C);
//
// There was no error, so the state machine is now idle.
//
g_ui32State = STATE_IDLE;
//
// This state is done.
//
break;
}
//
// Fall through to STATE_SEND_ACK.
//
}
//
// Send a read request, looking for the ACK to indicate that the write
// is done.
//
case STATE_SEND_ACK:
{
//
// Put the I2C master into receive mode.
//
SoftI2CSlaveAddrSet(&g_sI2C, SLAVE_ADDR, true);
//
// Perform a single byte read.
//
SoftI2CControl(&g_sI2C, SOFTI2C_CMD_SINGLE_RECEIVE);
//
// The next state is the wait for the ack.
//
g_ui32State = STATE_WAIT_ACK;
//
// This state is done.
//
break;
}
//
// The state for a single byte read.
//
case STATE_READ_ONE:
{
//
// Put the SoftI2C module into receive mode.
//
SoftI2CSlaveAddrSet(&g_sI2C, SLAVE_ADDR, true);
//
// Perform a single byte read.
//
SoftI2CControl(&g_sI2C, SOFTI2C_CMD_SINGLE_RECEIVE);
//
// The next state is the wait for final read state.
//
g_ui32State = STATE_READ_WAIT;
//
// This state is done.
//
break;
}
//
// The state for the start of a burst read.
//
case STATE_READ_FIRST:
{
//
// Put the SoftI2C module into receive mode.
//
SoftI2CSlaveAddrSet(&g_sI2C, SLAVE_ADDR, true);
//
// Start the burst receive.
//
SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_RECEIVE_START);
//
// The next state is the middle of the burst read.
//
g_ui32State = STATE_READ_NEXT;
//
// This state is done.
//
break;
}
//
// The state for the middle of a burst read.
//
case STATE_READ_NEXT:
{
//
// Read the received character.
//
*g_pui8Data++ = SoftI2CDataGet(&g_sI2C);
g_ui32Count--;
//
// Continue the burst read.
//
SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_RECEIVE_CONT);
//
// If there are two characters left to be read, make the next
// state be the end of burst read state.
//
if(g_ui32Count == 2)
{
g_ui32State = STATE_READ_FINAL;
}
//
// This state is done.
//
break;
}
//
// The state for the end of a burst read.
//
case STATE_READ_FINAL:
{
//
// Read the received character.
//
*g_pui8Data++ = SoftI2CDataGet(&g_sI2C);
g_ui32Count--;
//
// Finish the burst read.
//
SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_RECEIVE_FINISH);
//
// The next state is the wait for final read state.
//
g_ui32State = STATE_READ_WAIT;
//
// This state is done.
//
break;
}
//
// This state is for the final read of a single or burst read.
//
case STATE_READ_WAIT:
{
//
// Read the received character.
//
*g_pui8Data++ = SoftI2CDataGet(&g_sI2C);
g_ui32Count--;
//
// The state machine is now idle.
//
g_ui32State = STATE_IDLE;
//
// This state is done.
//
break;
}
}
}
//*****************************************************************************
//
// Write to the Atmel device.
//
//*****************************************************************************
void
AtmelWrite(uint8_t *pui8Data, uint32_t ui32Offset, uint32_t ui32Count)
{
//
// Save the data buffer to be written.
//
g_pui8Data = pui8Data;
g_ui32Count = ui32Count;
//
// Set the next state of the callback state machine based on the number of
// bytes to write.
//
if(ui32Count != 1)
{
g_ui32State = STATE_WRITE_NEXT;
}
else
{
g_ui32State = STATE_WRITE_FINAL;
}
//
// Set the slave address and setup for a transmit operation.
//
SoftI2CSlaveAddrSet(&g_sI2C, SLAVE_ADDR | (ui32Offset >> 8), false);
//
// Write the address to be written as the first data byte.
//
SoftI2CDataPut(&g_sI2C, ui32Offset);
//
// Start the burst cycle, writing the address as the first byte.
//
SoftI2CControl(&g_sI2C, SOFTI2C_CMD_BURST_SEND_START);
//
// Wait until the SoftI2C callback state machine is idle.
//
while(g_ui32State != STATE_IDLE)
{
}
}
//*****************************************************************************
//
// Read from the Atmel device.
//
//*****************************************************************************
void
AtmelRead(uint8_t *pui8Data, uint32_t ui32Offset, uint32_t ui32Count)
{
//
// Save the data buffer to be read.
//
g_pui8Data = pui8Data;
g_ui32Count = ui32Count;
//
// Set the next state of the callback state machine based on the number of
// bytes to read.
//
if(ui32Count == 1)
{
g_ui32State = STATE_READ_ONE;
}
else
{
g_ui32State = STATE_READ_FIRST;
}
//
// Start with a dummy write to get the address set in the EEPROM.
//
SoftI2CSlaveAddrSet(&g_sI2C, SLAVE_ADDR | (ui32Offset >> 8), false);
//
// Write the address to be written as the first data byte.
//
SoftI2CDataPut(&g_sI2C, ui32Offset);
//
// Perform a single send, writing the address as the only byte.
//
SoftI2CControl(&g_sI2C, SOFTI2C_CMD_SINGLE_SEND);
//
// Wait until the SoftI2C callback state machine is idle.
//
while(g_ui32State != STATE_IDLE)
{
}
}
//*****************************************************************************
//
// This is the interrupt handler for the Timer0A interrupt.
//
//*****************************************************************************
void
Timer0AIntHandler(void)
{
//
// Clear the timer interrupt.
// TODO: change this to whichever timer you are using.
//
TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
//
// Call the SoftI2C tick function.
//
SoftI2CTimerTick(&g_sI2C);
}
//*****************************************************************************
//
// This example demonstrates the use of the SoftI2C module to read and write an
// Atmel AT24C08A EEPROM.
//
//*****************************************************************************
int
main(void)
{
uint8_t pui8Data[16];
uint32_t ui32Idx;
//
// Set the clocking to run directly from the external crystal/oscillator.
// TODO: The SYSCTL_XTAL_ value must be changed to match the value of the
// crystal on your board.
//
SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
SYSCTL_XTAL_16MHZ);
//
// For this example, PortB[3:2] are used for the SoftI2C pins. GPIO port B
// needs to be enabled so these pins can be used.
// TODO: change this to whichever GPIO port(s) you are using.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
//
// For this example, Timer0 is used for the SoftI2C time base. This timer
// needs to be enabled before it can be used.
// TODO: change this to whichever timer you are using.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
//
// Configure the appropriate pins to be I2C instead of GPIO.
// TODO: change this to select the port/pin you are using.
//
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_2 | GPIO_PIN_3);
//
// Initialize the SoftI2C module, including the assignment of GPIO pins.
// TODO: change this to whichever GPIO pins you are using.
//
memset(&g_sI2C, 0, sizeof(g_sI2C));
SoftI2CCallbackSet(&g_sI2C, SoftI2CCallback);
SoftI2CSCLGPIOSet(&g_sI2C, GPIO_PORTB_BASE, GPIO_PIN_2);
SoftI2CSDAGPIOSet(&g_sI2C, GPIO_PORTB_BASE, GPIO_PIN_3);
SoftI2CInit(&g_sI2C);
//
// Enable the SoftI2C interrupt.
//
SoftI2CIntEnable(&g_sI2C);
//
// Configure the timer to generate an interrupt at a rate of 40 KHz. This
// will result in a I2C rate of 10 KHz.
// TODO: change this to whichever timer you are using.
// TODO: change this to whichever I2C rate you require.
//
TimerConfigure(TIMER0_BASE, TIMER_CFG_PERIODIC);
TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 40000);
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
TimerEnable(TIMER0_BASE, TIMER_A);
//
// Enable the timer interrupt.
// TODO: change this to whichever timer interrupt you are using.
//
IntEnable(INT_TIMER0A);
//
// Set up the serial console to use for displaying messages. This is
// just for this example program and is not needed for SoftI2C operation.
//
InitConsole();
//
// Display the example setup on the console.
//
UARTprintf("SoftI2C Atmel AT24C08A example\n");
//
// Write a data=address pattern into the first 16 bytes of the Atmel
// device.
//
UARTprintf("Write:");
for(ui32Idx = 0; ui32Idx < 16; ui32Idx++)
{
pui8Data[ui32Idx] = ui32Idx;
UARTprintf(" %02x", pui8Data[ui32Idx]);
}
UARTprintf("\n");
AtmelWrite(pui8Data, 0, 16);
//
// Read back the first 16 bytes of the Atmel device.
//
AtmelRead(pui8Data, 0, 16);
UARTprintf("Read :");
for(ui32Idx = 0; ui32Idx < 16; ui32Idx++)
{
UARTprintf(" %02x", pui8Data[ui32Idx]);
}
UARTprintf("\n");
//
// Tell the user that the test is done.
//
UARTprintf("Done.\n\n");
//
// Return no errors.
//
return(0);
}
/********************IIC²Ù×÷º¯Êý****************************/
#define SLAVE_ADDRESS 0x3C
#define CONF_ADOPT 0x01
#define CONF_UPLOAD 0x03
void IIC_Init()
{
/*************IIC³õʼ»¯***************/
SysCtlPeripheralEnable( SYSCTL_PERIPH_I2C1);//ʹÄÜIICÄ£¿é
SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOA);//ʹÄܶÔÓ¦µÄI/OÄ£¿é
GPIOPinConfigure(GPIO_PA6_I2C1SCL);//ÅäÖÃÏàÓ¦µÄI/O¹Ü½ÅΪSDA/SCL
GPIOPinConfigure(GPIO_PA7_I2C1SDA);
GPIOPinTypeI2CSCL(GPIO_PORTA_BASE,GPIO_PIN_6);
GPIOPinTypeI2C(GPIO_PORTA_BASE,GPIO_PIN_7);
I2CMasterInitExpClk(I2C1_BASE,SysCtlClockGet(),true);//Ö÷»úÅäÖÃģʽ£ºÆµÂÊ80MHZ,400KBP
I2CMasterEnable(I2C1_BASE);//Ö÷»úʹÄÜ
I2CSlaveEnable(I2C1_BASE);//ʹÄÜ´ÓÄ£¿é
I2CSlaveInit(I2C1_BASE, SLAVE_ADDRESS);//ÉèÖôÓÄ£¿éµØÖ·
}
uint8_t IIC_Read(uint8_t DevAddr,uint8_t RegAddr)//д´Ó»úµØÖ·£¬¼Ä´æÆ÷µØÖ·£¬Êý¾Ý¶ÁÈ¡º¯Êý
{
uint8_t iic_data=0;
I2CMasterSlaveAddrSet(I2C1_BASE, DevAddr, false);//ÓëÖ÷»ú¶ÔÓ¦µÄ´Ó»úµØÖ·ÉèÖ㬷¢ËÍÊý¾Ýģʽ
I2CMasterDataPut(I2C1_BASE, RegAddr);//·¢ËÍÒ»¸ö×ֽڵĴӻú¼Ä´æÆ÷µØÖ·
I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);//Ö÷»úÍ»·¢Æðʼ
//I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_SINGLE_SEND);//Ö÷»úµ¥´Î·¢ËÍ
while(I2CMasterBusy(I2C1_BASE));//µÈ´ý×ÜÏß¿ÕÏÐ
I2CMasterSlaveAddrSet(I2C1_BASE, DevAddr, true);//ÓëÖ÷»ú¶ÔÓ¦µÄ´Ó»úµØÖ·ÉèÖ㬽ÓÊÕÊý¾Ýģʽ
I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE);//Ö÷»úÍ»·¢½ÓÊÕÆðʼ
while(I2CMasterBusy(I2C1_BASE));//µÈ´ý×ÜÏß¿ÕÏÐ
iic_data = I2CMasterDataGet(I2C1_BASE);
return iic_data;
}
void IIC_Write(uint8_t slave_addr,uint8_t reg_addr,uint8_t data)
{
I2CMasterSlaveAddrSet(I2C1_BASE, slave_addr, false); //дÈë´Ó»úµØÖ·
I2CMasterDataPut(I2C1_BASE, reg_addr); //дÈë´Ó»ú¼Ä´æÆ÷µØÖ·
I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
while(I2CMasterBusy(I2C1_BASE))
{
}
I2CMasterDataPut(I2C1_BASE, data);
// Ö÷»ú¿ªÊ¼·¢ËÍÊý¾Ý
I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
/*while(I2CMasterBusy(I2C1_BASE))
{
}*/
I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_STOP);
/*while(I2CMasterBusy(I2C1_BASE))
{
}*/
//return 1;
}
这是我今天参考这个官方的程序写的,但是调试的时候会一直卡在等待总线哪里,程序 上 还有问题么?
估计还是你初始化的问题,说明初始化就不OK。
I2CMasterEnable(I2C1_BASE);//Ö÷»úʹÄÜ
I2CSlaveEnable(I2C1_BASE);//ʹÄÜ´ÓÄ£¿é
这里应该用的是主机模式,你怎么从机都使能了。
我把从机使能屏蔽了,调试了一下,还是会不停执行这条while(I2CMasterBusy(I2C1_BASE));//µÈ´ý×ÜÏß¿ÕÏÐ,总线一直在忙什么,可以叫他抽空不忙不
T抓波形吧,你看看你的发送指令是否已经发出去信息了呢?或者用IO模拟看看,换I2C0试试