SPI+EEPROM读写问题
开发环境:Silicon Laboratories IDE+C8051F340+EEPROM IN24LC16
目的:想向EEPROM中写入一串数据,然后再读出来,并显示在UART0上
状况:用Watch调试查看时发现在读的时候中间变量test_byte并没有发生变化,最终导致读出的结果不对,不知道是没有写进入,还是写错了,抑或读的不对,希望各位大侠解答
#include <C8051F340.h> // SFR declarations
#include <stdio.h> // printf is declared here
sfr16 TMR2 = 0xCC; // Timer2 low and high bytes together
#define uchar unsigned char
#define UINT unsigned int
#define BAUDRATE 115200
#define SYSCLK 24000000
#define F_SCK_MAX 2000000
#define T_NSS_DISABLE_MIN 500
#define EEPROM_CMD_RDSR 0x05
sbit LED_1 = P3^4;
sbit LED_2 = P3^5;
void PCA0_Init (void);
void OSCILLATOR_Init (void);
void PORT_Init (void);
void TIMER2_Init (void);
void UART0_Init (void);
void SPI0_Init (void);
void Init_Device (void);
void Delay_us (uchar time_us);
void Delay_ms (uchar time_ms);
void EEPROM_Write (UINT address, uchar value);
uchar EEPROM_Read (UINT address);
void main (void)
{
UINT address =0x0000;
uchar test_byte;
UINT i ;
bit flag = 1;
Init_Device ();
LED_1 = 1;
LED_2 = 1;
for (i = 0; i < 7; i++)
{
test_byte = 0xAA;
IE &= 0x7F ;
EEPROM_Write (address, test_byte);
IE |= 0x80 ;
address += 1;
printf ("%02x ", (UINT)test_byte);
}
test_byte = 0x00 ;
// Verify
for (i = 0x0000; i < address; i+=2 )
{
IE &= 0x7F ;
test_byte = EEPROM_Read (i);
IE |= 0x80 ;
if (test_byte == 0xAA)
{
LED_1 = 0;
printf ("right at %u\n", i);
}
else {
printf("wrong at %u\n",i);
flag = 0;
}
}
while (flag) // Loop forever
{
LED_1 = ~LED_1; // Flash LED when done (all verified)
LED_2 = ~LED_2;
Delay_ms (200);
}
}
void PCA0_Init (void)
{
PCA0MD &= ~0x40;
PCA0MD = 0x00;
}
void OSCILLATOR_Init (void)
{
int i = 0;
OSCICN = 0x83;
CLKMUL = 0x80;
for (i = 0; i < 20; i++); // Wait 5us for initialization
CLKMUL |= 0xC0;
while ((CLKMUL & 0x20) == 0);
CLKSEL = 0x02;
}
void PORT_Init (void)
{
P1MDOUT = 0x0D; //spi sck miso mosi cs配置
P2MDOUT = 0x00;
P2SKIP = 0x03;
P3MDOUT = 0x30; //LED D1 D2
P3SKIP = 0x0C;
XBR0 = 0x03; //spi i/o使能,UART TX0,RX0链接到P0.4,P0.5
XBR1 = 0x40; //7:弱上拉使能,6:交叉开关使能
}
void TIMER2_Init (void)
{
CKCON |= 0x10;
}
void UART0_Init (void)
{
SCON0 = 0x10; // SCON0: 8-bit variable bit rate
// level of STOP bit is ignored
// RX enabled
// ninth bits are zeros
// clear RI0 and TI0 bits
if (SYSCLK/BAUDRATE/2/256 < 1)
{
TH1 = -(SYSCLK/BAUDRATE/2);
CKCON &= ~0x0B; // T1M = 1; SCA1:0 = xx
CKCON |= 0x08;
}
else if (SYSCLK/BAUDRATE/2/256 < 4)
{
TH1 = -(SYSCLK/BAUDRATE/2/4);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 01
CKCON |= 0x09;
}
else if (SYSCLK/BAUDRATE/2/256 < 12)
{
TH1 = -(SYSCLK/BAUDRATE/2/12);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 00
} else
{
TH1 = -(SYSCLK/BAUDRATE/2/48);
CKCON &= ~0x0B; // T1M = 0; SCA1:0 = 10
CKCON |= 0x02;
}
TL1 = TH1; // init Timer1
TMOD &= ~0xf0; // TMOD: timer 1 in 8-bit autoreload
TMOD |= 0x20;
TR1 = 1; // START Timer1
TI0 = 1; // Indicate TX0 ready
}
//-----------------------------------------
// SPI0_Init
//-----------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configures SPI0 to use 4-wire Single-Master mode. The SPI timing is
// configured for Mode 0,0 (data centered on first edge of clock phase and
// SCK line low in idle state). The SPI clock is set to 2 MHz. The NSS pin
// is set to 1.
//
//-----------------------------------------
void SPI0_Init()
{
SPI0CFG = 0x40; //6:允许主方式,工作在主器件方式
SPI0CN = 0x0D; // 3-2:四线单主方式,0:使能spi0
// The equation for SPI0CKR is (SYSCLK/(2*F_SCK_MAX))-1
SPI0CKR = (SYSCLK/(2*F_SCK_MAX)) - 1;
}
//-----------------------------------------
// Init_Device
//-----------------------------------------
//
// Return Value : None
// Parameters : None
//
// Calls all device initialization functions.
//
//-----------------------------------------
void Init_Device (void)
{
PCA0_Init ();
OSCILLATOR_Init ();
PORT_Init ();
TIMER2_Init ();
UART0_Init ();
SPI0_Init ();
}
//-----------------------------------------
// Support Subroutines
//-----------------------------------------
//-----------------------------------------
// Delay_us
//-----------------------------------------
void Delay_us (uchar time_us)
{
TR2 = 0; // Stop timer
TF2H = 0; // Clear timer overflow flag
TMR2 = -( (UINT)(SYSCLK/1000000) * (UINT)(time_us) );
TR2 = 1; // Start timer
while (!TF2H); // Wait till timer overflow occurs
TR2 = 0; // Stop timer
}
//-----------------------------------------
// Delay_ms
//-----------------------------------------
//
// Return Value : None
// Parameters : 1. time_ms - time delay in milliseconds
// range: 1 to 255
//
// Creates a delay for the specified time (in milliseconds) using TIMER2. The
// time tolerance is approximately +/-50 ns (1/SYSCLK + function call time).
//
//-----------------------------------------
void Delay_ms (uchar time_ms)
{
uchar i;
while(time_ms--)
for(i = 0; i< 10; i++) // 10 * 100 microsecond delay
Delay_us (100);
}
//-----------------------------------------
// EEPROM_Write
//-----------------------------------------
//
//-----------------------------------------
void EEPROM_Write (UINT address, uchar value)
{
// Writing a byte to the EEPROM is a five-step operation.
// Step1: Set the Write Enable Latch to 1
NSSMD0 = 0; // Step1.1: Activate Slave Select
SPI0DAT = 0xA2; // Step1.2: Send the WREN command
while (!SPIF); // Step1.3: Wait for end of transfer
SPIF = 0; // Step1.4: Clear the SPI intr. flag
NSSMD0 = 1; // Step1.5: Deactivate Slave Select
Delay_us (1); // Step1.6: Wait for at least
// T_NSS_DISABLE_MIN
// Step3: Send the EEPROM destination address (MSB first)
SPI0DAT = (uchar)((address >> 8) & 0x00FF); //一次只能传输8位数据,故先传送16位地址的高8位
while (!SPIF);
SPIF = 0;
SPI0DAT = (uchar)(address & 0x00FF);
while (!SPIF);
SPIF = 0;
// Step4: Send the value to write
SPI0DAT = value;
while (!SPIF);
SPIF = 0;
NSSMD0 = 1;
Delay_us (1);
// Step5: Poll on the Write In Progress (WIP) bit in Read Status Register
do
{
NSSMD0 = 0; // Activate Slave Select
SPI0DAT = EEPROM_CMD_RDSR; // Send the Read Status Register command
while (!SPIF); // Wait for the command to be sent out
SPIF = 0;
SPI0DAT = 0; // Dummy write to output serial clock
while (!SPIF); // Wait for the register to be read
SPIF = 0;
NSSMD0 = 1; // Deactivate Slave Select after read
Delay_us (1);
} while( (SPI0DAT & 0x01) == 0x01 );
}
//-----------------------------------------
// EEPROM_Read
//-----------------------------------------
uchar EEPROM_Read (UINT address)
{
// Reading a byte from the EEPROM is a three-step operation.
// Step1: Send the READ command
NSSMD0 = 0; // Activate Slave Select
SPI0DAT = 0xA3;
while (!SPIF);
SPIF = 0;
// Step2: Send the EEPROM source address (MSB first)
SPI0DAT = (uchar)((address >> 8) & 0x00FF);
while (!SPIF);
SPIF = 0;
SPI0DAT = (uchar)(address & 0x00FF);
while (!SPIF);
SPIF = 0;
// Step3: Read the value returned
SPI0DAT = 0; // Dummy write to output serial clock
while (!SPIF); // Wait for the value to be read
SPIF = 0;
NSSMD0 = 1; // Deactivate Slave Select
Delay_us (1);
return SPI0DAT;
}
//-----------------------------------------
// End Of File
//-----------------------------------------
[解决办法]
EEPROM要先擦除,后写。擦除是一个block一个block的擦的。
[解决办法]
IN24LC16
的代码很多,搜到之后使用IO模拟,很容易实现。
[解决办法]