|
#include <stdio.h>
#include "stm32f4xx.h"
#include "sys.h"
#include <string.h>
static GPIO_InitTypeDef GPIO_InitStruct;
static NVIC_InitTypeDef NVIC_InitStructure;
static USART_InitTypeDef USART_InitStructure;
void delay_us(uint32_t nus)
{
SysTick->CTRL = 0; // 關閉系統(tǒng)定時器
SysTick->LOAD = nus*(SystemCoreClock/1000000); // nus *1us延時,這個計數(shù)值
SysTick->VAL = 0; // 清空標志位
SysTick->CTRL = 5; // 使能系統(tǒng)定時器工作,時鐘源為系統(tǒng)時鐘168MHz
while ((SysTick->CTRL & 0x00010000)==0); // 檢查CTRL寄存器的16bit是否置1,若置1,就代表計數(shù)完畢
SysTick->CTRL = 0; // 關閉系統(tǒng)定時器
}
void delay_ms(uint32_t nms)
{
while(nms--)
{
SysTick->CTRL = 0; // 關閉系統(tǒng)定時器
SysTick->LOAD = (SystemCoreClock/1000); // 1ms延時,這個計數(shù)值
SysTick->VAL = 0; // 清空標志位
SysTick->CTRL = 5; // 使能系統(tǒng)定時器工作,時鐘源為系統(tǒng)時鐘168MHz
while ((SysTick->CTRL & 0x00010000)==0); // 檢查CTRL寄存器的16bit是否置1,若置1,就代表計數(shù)完畢
SysTick->CTRL = 0; // 關閉系統(tǒng)定時器
}
}
int fputc(int ch,FILE *file)
{
USART_SendData(USART1,ch);
//等待發(fā)送完畢
while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
return ch;
}
void usart1_init(uint32_t baud)
{
//端口A硬件時鐘使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
//串口1硬件時鐘使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
//配置硬件,配置GPIO,端口A,第9 10引腳
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9|GPIO_Pin_10;//第9 10引腳
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF; //復用功能模式
GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed; //引腳高速工作,收到指令立即工作;缺點:功耗高
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP; //增加輸出電流的能力
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL; //不需要上下拉電阻
GPIO_Init(GPIOA,&GPIO_InitStruct);
//將PA9引腳連接到串口1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
//將PA10引腳連接到串口1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
USART_InitStructure.USART_BaudRate = baud; //波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位數(shù)據(jù)位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //1個停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //無校驗位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不需要流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //允許串口接收和發(fā)送數(shù)據(jù)
USART_Init(USART1, &USART_InitStructure);
//接收數(shù)據(jù)后觸發(fā)中斷
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
/* 配置串口1 */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_Cmd(USART1, ENABLE);
}
#define SCL_W PBout(8)
#define SDA_W PBout(9)
#define SDA_R PBin(9)
void at24c02_init(void)
{
//使能端口B的硬件時鐘
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8|GPIO_Pin_9; //第 8 9 個引腳
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT; //輸出模式
GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed; //引腳高速工作,收到指令立即工作;缺點:功耗高
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP; //增加輸出電流的能力
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL; //不需要上下拉電阻
GPIO_Init(GPIOB,&GPIO_InitStruct);
//只要是輸出模式,肯定會有初始電平狀態(tài),看時序圖,空閑狀態(tài)為高電平
SCL_W=1;
SDA_W=1;
}
void sda_pin_mode(GPIOMode_TypeDef pin_mode)
{
//配置硬件,配置GPIO,端口F,第9個引腳
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9; //第9 個引腳
GPIO_InitStruct.GPIO_Mode=pin_mode; //輸出模式
GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed; //引腳高速工作,收到指令立即工作;缺點:功耗高
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP; //增加輸出電流的能力
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL; //不需要上下拉電阻
GPIO_Init(GPIOB,&GPIO_InitStruct);
}
void i2c_start(void)
{
//保證SDA引腳為輸出模式
sda_pin_mode(GPIO_Mode_OUT);
SDA_W=1;
SCL_W=1;
delay_us(5);
SDA_W=0;
delay_us(5);
SCL_W=0;//總線進入忙狀態(tài)
delay_us(5);
}
void i2c_stop(void)
{
//保證SDA引腳為輸出模式
sda_pin_mode(GPIO_Mode_OUT);
SDA_W=0;
SCL_W=1;
delay_us(5);
SDA_W=1;
delay_us(5);
}
void i2c_send_byte(uint8_t byte)
{
int32_t i=0;
//保證SDA引腳為輸出模式
sda_pin_mode(GPIO_Mode_OUT);
SDA_W=0;
SCL_W=0;
delay_us(5);
//最高有效位優(yōu)先傳輸,通過時序圖觀察到
for(i=7; i>=0; i--)
{
//檢測對應的bit位是1還是0
if(byte & (1<<i))
SDA_W=1;
else
SDA_W=0;
delay_us(5);
//時鐘線拉高,數(shù)據(jù)有效
SCL_W=1;
delay_us(5);
//時鐘線拉低,數(shù)據(jù)變更
SCL_W=0;
delay_us(5);
}
}
uint8_t i2c_recv_byte(void)
{
uint8_t d=0;
int32_t i;
//保證SDA引腳為輸入模式
sda_pin_mode(GPIO_Mode_IN);
for(i=7; i>=0; i--)
{
//時鐘線拉高,數(shù)據(jù)有效
SCL_W=1;
delay_us(5);
//讀取SDA引腳電平
if(SDA_R)
d|=1<<i;
//時鐘線拉低,保持占用總線,總線是忙狀態(tài)
SCL_W=0;
delay_us(5);
}
return d;
}
void i2c_ack(uint8_t ack)
{
//保證SDA引腳為輸出模式
sda_pin_mode(GPIO_Mode_OUT);
SDA_W=0;
SCL_W=0;
delay_us(5);
if(ack)
SDA_W=1;
else
SDA_W=0;
delay_us(5);
//時鐘線拉高,數(shù)據(jù)有效
SCL_W=1;
delay_us(5);
//時鐘線拉低,數(shù)據(jù)變更
SCL_W=0;
delay_us(5);
}
uint8_t i2c_wait_ack(void)
{
uint8_t ack=0;
//保證SDA引腳為輸入模式
sda_pin_mode(GPIO_Mode_IN);
//時鐘線拉高,數(shù)據(jù)有效
SCL_W=1;
delay_us(5);
//讀取SDA引腳電平
if(SDA_R)
ack=1;//無應答
else
ack=0;//有應答
//時鐘線拉低,保持占用總線,總線是忙狀態(tài)
SCL_W=0;
delay_us(5);
return ack;
}
int32_t at24c02_write(uint8_t word_address,uint8_t *data,uint8_t len)
{
uint8_t ack=0;
uint8_t *p=data;
//發(fā)送起始信號
i2c_start();
//發(fā)送設備尋址,從機地址寫訪問地址0xA0
i2c_send_byte(0xA0);
//等待對方應答
ack=i2c_wait_ack();
if(ack)
{
printf("device address error\r\n");
return -1;
}
//發(fā)送訪問數(shù)據(jù)存儲地址
i2c_send_byte(word_address);
//等待對方應答
ack=i2c_wait_ack();
if(ack)
{
printf("word address error\r\n");
return -2;
}
//連續(xù)寫入數(shù)據(jù)
while(len--)
{
//發(fā)送要寫入的數(shù)據(jù)
i2c_send_byte(*p++);
//等待對方應答
ack=i2c_wait_ack();
if(ack)
{
printf("write data error\r\n");
return -3;
}
}
//結束通信
i2c_stop();
printf("write success\r\n");
return 0;
}
int32_t at24c02_read(uint8_t word_address,uint8_t *data,uint8_t len)
{
uint8_t ack=0;
uint8_t *p=data;
//發(fā)送起始信號
i2c_start();
//發(fā)送設備尋址,從機地址寫訪問地址0xA0
i2c_send_byte(0xA0);
//等待對方應答
ack=i2c_wait_ack();
if(ack)
{
printf("device address with write error\r\n");
return -1;
}
//發(fā)送訪問數(shù)據(jù)存儲地址
i2c_send_byte(word_address);
//等待對方應答
ack=i2c_wait_ack();
if(ack)
{
printf("word address error\r\n");
return -2;
}
//重新發(fā)送起始信號
i2c_start();
//發(fā)送設備尋址,從機地址讀訪問地址0xA1
i2c_send_byte(0xA1);
//等待對方應答
ack=i2c_wait_ack();
if(ack)
{
printf("device address with read error\r\n");
return -3;
}
len=len-1;
//連續(xù)寫入數(shù)據(jù)
while(len--)
{
//讀取數(shù)據(jù)
*p++=i2c_recv_byte();
//主動發(fā)應答信號
i2c_ack(0);
}
//讀取最后一個數(shù)據(jù)
*p=i2c_recv_byte();
//主動發(fā)無應答信號
i2c_ack(1);
//結束通信
i2c_stop();
printf("read success\r\n");
return 0;
}
//主函數(shù)
int main(void)
{
uint8_t buf[8]={1,2,3,4,5,6,7,8};
uint32_t i;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//使能端口F的硬件時鐘,端口F才能工作,說白了就是對端口F上電
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
//配置硬件,配置GPIO,端口F,第9個引腳
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9; //第9 個引腳
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT; //輸出模式
GPIO_InitStruct.GPIO_Speed=GPIO_High_Speed; //引腳高速工作,收到指令立即工作;缺點:功耗高
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP; //增加輸出電流的能力
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL; //不需要上下拉電阻
GPIO_Init(GPIOF,&GPIO_InitStruct);
//配置串口1波特率為115200bps
usart1_init(115200);
at24c02_init();
printf("This is at24c02 test\r\n");
printf("at24c02:write addr at 0,data is 1 ~ 8\r\n");
at24c02_write(0,buf,8);
delay_ms(10);
memset(buf,0,sizeof buf);
at24c02_read(0,buf,8);
printf("read data is:");
for(i=0; i<8; i++)
printf("%02X ",buf[i]);
printf("\r\n");
while(1)
{
}
}
void USART1_IRQHandler(void)
{
uint8_t d;
//檢查串口1是否接收到數(shù)據(jù)
if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET)
{
//讀取數(shù)據(jù)
d = USART_ReceiveData(USART1);
//清空標志位
USART_ClearITPendingBit(USART1,USART_IT_RXNE);
}
}
|
評分
-
查看全部評分
|