STM32F103C8T6单⽚机通过I2C库函数来读写24C02存储器电路连接:SCL和SDA分别接到PB6和PB7上,并都外接上10kΩ上拉电阻。
电路板如下图所⽰:
最左边的4个排针接的是电源和串⼝。
由于板上没有任何外部晶振,所以在Keil中建好⼯程后, 要将RTE/Device/STM32F103C8/system_stm32f10x.c中的
SYSCLK_FREQ_72MHz的定义注释掉,防⽌SystemInit函数打开HSE晶振。
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
#define SYSCLK_FREQ_24MHz 24000000
#el
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz 24000000 */
/* #define SYSCLK_FREQ_36MHz 36000000 */
/* #define SYSCLK_FREQ_48MHz 48000000 */
/* #define SYSCLK_FREQ_56MHz 56000000 */
/* #define SYSCLK_FREQ_72MHz 72000000 */
#endif
板⼦有两种程序下载⽅式。⼀种是通过J-Link仿真器,在Keil中下载。另⼀种是按下板上的⽩⾊开关,将BOOT0拉⾼(BOOT1=PB2必须通过10kΩ的电阻接地),然后⽤STMicroelectronics的FlashLoader通过串⼝1下载编译好的hex⽂件。
板上LED灯串联的电阻是500Ω左右(由两个1kΩ的电阻并联⽽成),接到了PA8上,⾼电平点亮,本实验中没有⽤到。
复位电路所⽤的电容是0.1μF 50V的电解电容(104),是51/AVR的单⽚机所⽤的10μF的1%。
【程序1:普通⽅式】
#include <stdio.h>
#include <stm32f10x.h>
int fputc(int ch, FILE *fp)
{
if (fp == stdout)
{
if (ch == '\n')
{
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, '\r');
}
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, ch);
}
return ch;
}
// 发送开始信号和从机地址(传输模式)
void start(void)
{
if (I2C1->SR1 || I2C1->SR2)
printf("error!\n");
restart:
I2C_GenerateSTART(I2C1, ENABLE);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR); // 等待开始信号发送完毕
I2C_SendData(I2C1, 0xa0); // 从机地址(传输模式)
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR) // 等待从机确认 {
if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET)
{
翀五笔怎么打// 若从机未响应, 则重试
// 执⾏了写操作后需要等待⼀段时间才能执⾏其他命令
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
//printf("NACK!\n");
goto restart;
}
绝对值怎么打}
}
uint8_t read(uint8_t addr)
{
start();
I2C_SendData(I2C1, addr); // 发送存储器地址
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
I2C_GenerateSTART(I2C1, ENABLE); // RESTART
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_SendData(I2C1, 0xa1); // 从机地址(接收模式)
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == ERROR);
I2C_GenerateSTOP(I2C1,ENABLE); // 接收最后⼀字节数据前先准备好STOP信号
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) == ERROR); // 等待数据接收完毕
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET); // 等待停⽌信号发送完毕
return I2C_ReceiveData(I2C1);
}
void write(uint8_t addr, uint8_t value)
{
start();
start();
I2C_SendData(I2C1, addr); // 前两个数据可连发, ⽆需等待TXE置位
I2C_SendData(I2C1, value);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR); // 等待数据完全发送完毕
苏轼的故事
I2C_GenerateSTOP(I2C1,ENABLE);
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET); // 等待停⽌信号发送完毕
}
void read_more(uint8_t addr, char *data, uint8_t len)
{
start();
I2C_SendData(I2C1, addr);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
I2C_GenerateSTART(I2C1, ENABLE);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_SendData(I2C1, 0xa1);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == ERROR);
I2C_AcknowledgeConfig(I2C1, ENABLE);
while (len--)
{
if (len == 0)
{
I2C_AcknowledgeConfig(I2C1, DISABLE);
I2C_GenerateSTOP(I2C1,ENABLE); // 接收最后⼀字节数据前先准备好STOP信号
}
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED) == ERROR); // 等待当前数据接收完毕
*data++ = I2C_ReceiveData(I2C1);
}
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET); // 等待停⽌信号发送完毕
}
void write_more(uint8_t addr, const char *data, uint8_t len)
{
start();
I2C_SendData(I2C1, addr);
while (len--)
{
I2C_SendData(I2C1, *data++);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING) == ERROR); // 等待TXE
}
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR); // 等待全部数据发送完毕
I2C_GenerateSTOP(I2C1,ENABLE);
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET); // 等待停⽌信号发送完毕
}
int main(void)
{
char str[20];
GPIO_InitTypeDef gpio;
I2C_InitTypeDef i2c;
USART_InitTypeDef usart;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_USART1, ENABLE);
// 串⼝发送引脚设为复⽤推挽输出
gpio.GPIO_Mode = GPIO_Mode_AF_PP;
gpio.GPIO_Pin = GPIO_Pin_9;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio);
// I2C引脚设为复⽤开漏输出
gpio.GPIO_Mode = GPIO_Mode_AF_OD;
gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOB, &gpio);
USART_StructInit(&usart);
usart.USART_BaudRate = 115200;
usart.USART_Mode = USART_Mode_Tx;
USART_Init(USART1, &usart);
USART_Cmd(USART1, ENABLE);
I2C_StructInit(&i2c);
i2c.I2C_ClockSpeed = 100000;
I2C_Init(I2C1, &i2c);
I2C_Cmd(I2C1, ENABLE);
write(17, 0x31);
printf("read: 0x%02x\n", read(17));
write_more(17, "Hello!", 7); // 区域16~23
read_more(17, str, sizeof(str));
printf("str: %s\n", str);
write_more(8, "12345678ABCDEFG", 16); // 先将前8个字符写⼊地址8~15处, 然后回到地址8处写⼊剩下的字符, 包括最后的\0
read_more(8, str, sizeof(str));
printf("str: %s\n", str);
printf("I2C1->SR1=0x%04x, I2C1->SR2=0x%04x\n", I2C_ReadRegister(I2C1, I2C_Register_SR1), I2C_ReadRegister(I2C1, I2C_Register_SR2));
while (1)
__WFI();
}
【程序运⾏结果1】
read: 0x31
str: Hello!
str: ABCDEFG
I2C1->SR1=0x0000, I2C1->SR2=0x0000
两个SR寄存器的值都为0表明I2C正常⼯作。
【程序2:DMA⽅式】
#include <stdio.h>
#include <stm32f10x.h>
DMA_InitTypeDef dma;家装设计施工
#define WRITE
#ifdef WRITE
const char eep_data[] = "The SDIO does not have an SPI-compatible communication mode. The SD memory card protocol is a supert of the MultiMediaCard pr #endif
int fputc(int ch, FILE *fp)
{
if (fp == stdout)
{
if (ch == '\n')
{
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, '\r');
}
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
USART_SendData(USART1, ch);
}
return ch;
}
金英柱// 发送开始信号和从机地址(传输模式)
void start(void)
{
仲夏之梦if (I2C1->SR1 || I2C1->SR2)
printf("error!\n");
restart:
I2C_GenerateSTART(I2C1, ENABLE);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR); // 等待开始信号发送完毕
I2C_SendData(I2C1, 0xa0); // 从机地址(传输模式)
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED) == ERROR) // 等待从机确认 {
if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF) == SET)
{
// 若从机未响应, 则重试
// 执⾏了写操作后需要等待⼀段时间才能执⾏其他命令
I2C_ClearFlag(I2C1, I2C_FLAG_AF);
//printf("NACK!\n");
goto restart;
}
}
}
void read(uint8_t addr, char *data, uint16_t len)
{
dma.DMA_BufferSize = len;
dma.DMA_DIR = DMA_DIR_PeripheralSRC;
dma.DMA_MemoryBaAddr = (uint32_t)data;
DMA_Init(DMA1_Channel7, &dma);
深刻的近义词DMA_Cmd(DMA1_Channel7, ENABLE);
start();
I2C_SendData(I2C1, addr);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED) == ERROR);
I2C_GenerateSTART(I2C1, ENABLE);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT) == ERROR);
I2C_SendData(I2C1, 0xa1);
while (I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED) == ERROR);
I2C_DMACmd(I2C1, ENABLE);
I2C_DMALastTransferCmd(I2C1, ENABLE);
I2C_AcknowledgeConfig(I2C1, ENABLE);
while (DMA_GetFlagStatus(DMA1_FLAG_TC7) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC7);
DMA_Cmd(DMA1_Channel7, DISABLE);
I2C_GenerateSTOP(I2C1, ENABLE);
I2C_DMACmd(I2C1, DISABLE);
I2C_DMALastTransferCmd(I2C1, DISABLE);
I2C_AcknowledgeConfig(I2C1, DISABLE);
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY) == SET);
}
void write(uint8_t addr, const char *data, uint8_t len)
{
fly的第三人称单数形式dma.DMA_BufferSize = len;
dma.DMA_DIR = DMA_DIR_PeripheralDST;