★ 可以直接複製貼上到 C 語言開發環境中,此程式碼可以直接編譯執行(只要你配置好開發環境與硬體)。

說明:這篇程式碼有點長~~~,不過可以保證編譯可以通過,PB6=I2C-SCL、PB7=I2C-SDA、PB10=UART-Tx、PB11=UART-Rx,UART 包率為 9600,祝大家都可以成功 (至少我成功了...哈哈哈)

程式碼:

#include "stm32f4xx.h"
#include "stdio.h"
 
#define DS1307_I2C_ADDRESS 0x68 << 1 // DS1307  I²C 地址
 
int i;
int y; // 年
int m, d, w, h, mi, s; // 月/日/週/時/分/秒
 
void init_I2C1(){
 
    GPIO_InitTypeDef GPIO_InitStruct;
    I2C_InitTypeDef I2C_InitStruct;
 
    // 啟用 I2C1 的 RCC 時鐘
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
    // 啟用 GPIOB 時鐘,主要是啟用 PB6 腳位的 SCL 時鐘、PB7 腳位的 SDA 時鐘
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
 
    /* 設定 SCL 與 SDA 腳位
    *
    * 配對腳位:
    *         SCL = PB6 
    *         SDA = PB7 
    */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // 使用 PB6 與 PB7
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // 設定腳位為 覆用 ( AF - Alternate Function )
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // 設定 GPIO 速度為 50 MHz
    GPIO_InitStruct.GPIO_OType = GPIO_OType_OD; // set output to open drain --> the line has to be only pulled low, not driven high
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // 使用上拉電阻
    GPIO_Init(GPIOB, &GPIO_InitStruct); // 初始化 GPIOB
 
    // 連接 I2C1 到 AF 
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1); // SCL
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1); // SDA
 
    // 設定 I2C1 
    I2C_InitStruct.I2C_ClockSpeed = 100000; // 設定 I2C 時鐘速度為 100kHz
    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; // I2C 模式
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; // 50% duty cycle --> standard
    I2C_InitStruct.I2C_OwnAddress1 = 0x00; // own address, not relevant in master mode
    I2C_InitStruct.I2C_Ack = I2C_Ack_Disable; // disable acknowledge when reading (can be changed later on)
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 設定 I2C 地址長度為 7 bit
    I2C_Init(I2C1, &I2C_InitStruct); // 初始化 I2C1
 
    // 啟用 I2C1
    I2C_Cmd(I2C1, ENABLE);
 
}
 
/* 發送開始信號
 * 發送到 "從設備 (Slave Device)" 地址 + R/W bit
 * 
 * 參數:
 * I2Cx --> I2C 外設,例如:I2C1
 * address --> 7 bit 的 "從設備 (Slave Device)" 地址
 * direction --> 設定方向,例如:
 * I2C_Direction_Tranmitter 為 主發送模式
 * I2C_Direction_Receiver 為 主接收模式
 */
void I2C_start(I2C_TypeDef* I2Cx, uint8_t address, uint8_t direction){
    // 等待 I2C1 不忙的時候...
    while(I2C_GetFlagStatus(I2Cx, I2C_FLAG_BUSY));
 
    // 對 I2C1 發送啟動信號
    I2C_GenerateSTART(I2Cx, ENABLE);
 
    // 等待 I2C1 EV5 --> 從 從設備 (Slave Device) 確認啟動信號 
    while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT));
 
    // Send slave Address for write 
    I2C_Send7bitAddress(I2Cx, address, direction);
 
    /* 等待 I2C1 EV6, 並判斷 I²C 方向:
     * 如果是 I2C_Direction_Tranmitter 則設定為 主發送模式
     * 如果是 I2C_Direction_Receiver 則設定為 主接收模式
     */ 
    if(direction == I2C_Direction_Transmitter){
        while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
    } else if(direction == I2C_Direction_Receiver){
        while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
    }
}
 
/* 發送一個 byte 到 "從設備 (Slave Device)"
 *
 * 參數:
 *I2Cx --> I2C 的外設,例如:I2C1 
 *data --> 要發送的 byte 資料
 */
void I2C_write(I2C_TypeDef* I2Cx, uint8_t data)
{
I2C_SendData(I2Cx, data);
// 等待 I2C1 EV8_2 --> 已發送一個 byte
while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
}
 
/* 從 "從設備 (Slave Device)" 讀取一個 byte
 * 並請求後面一個 byte
 */
uint8_t I2C_read_ack(I2C_TypeDef* I2Cx){
uint8_t data;
    // 啟用 確認設定接收資料
    I2C_AcknowledgeConfig(I2Cx, ENABLE);
    // 等待接收到一個 byte
    while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
    // 從 I²C 佔存器讀取一個 byte 並回傳
    data = I2C_ReceiveData(I2Cx);
    return data;
}
 
/* 從 "從設備 (Slave Device)" 讀取一個 byte
 * 且之後就不再接收資料
 */
uint8_t I2C_read_nack(I2C_TypeDef* I2Cx){
    uint8_t data;
    // disabe acknowledge of received data
    // nack also generates stop condition after last byte received
    // see reference manual for more info
    I2C_AcknowledgeConfig(I2Cx, DISABLE);
    I2C_GenerateSTOP(I2Cx, ENABLE);
    // 等待收到一個 byte
    while( !I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED) );
    // 從 I²C 佔存器讀取一個 byte 並回傳
    data = I2C_ReceiveData(I2Cx);
    return data;
}
 
/* 發送停止信號
 * 釋放 I²C 匯流排
 */
void I2C_stop(I2C_TypeDef* I2Cx){
    // 停止 I2C1
    I2C_GenerateSTOP(I2Cx, ENABLE);
}
 
void My_Usart3_Printf(char *string){
    while(*string){
        /* 傳送訊息至 USART3 */
        USART_SendData(USART3, (unsigned short int) *string++);
 
        /* 等待訊息傳送完畢 */
        while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET);
    }
}
 
void Init_UART(){
    /******** 宣告 USART、GPIO 結構體 ********/
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
 
    /******** 啟用 GPIOC、USART3 的 RCC 時鐘 ********/
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);  
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
  
    /******** 將 PC10、PC11 連接至 USART3 ********/
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_USART3);
    GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_USART3);
 
    /******** 設定 PC10 為 Tx 覆用  ********/
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 使用推挽式輸出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 使用上拉電阻
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 設置為覆用
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // 設定第 10 腳
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 設定 GPIO 速度為 50 MHz
    GPIO_Init(GPIOC, &GPIO_InitStructure); // 套用以上 GPIO 設置,並初始化 GPIOC
 
    /******** 設定 PC11 為 Rx 覆用  ********/
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 設置為覆用
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; // 設定第 11 腳
    GPIO_Init(GPIOC, &GPIO_InitStructure); // 套用以上 GPIO 設置,並初始化 GPIOC
 
    /******** USART 基本參數設定 ********/
    USART_InitStructure.USART_BaudRate = 9600; // 設定 USART 包率 (每秒位元數) 為 9600
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 設定 USART 傳輸的資料位元為 8
    USART_InitStructure.USART_StopBits = USART_StopBits_1; // 設定 USART 停止位元為 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;  // 設定 USART 模式為 Rx (接收) 、 Tx (傳送)
    USART_Init(USART3, &USART_InitStructure); // 套用以上 USART 設置,並初始化UART3
    
    /******** 啟用 USART3 ********/
    USART_Cmd(USART3, ENABLE);
}
 
// BCD 轉 DEC
int bcdTodec(int val){
    return ((val / 16 * 10) + (val % 16));
}
 
// DEC 轉 BCD
int decToBcd(int val){
    return ((val / 10 * 16) + (val % 10));
}
 
// 設定時間
void setTime(int y, int m, int d, int w, int h, int mi, int s){
    
    I2C_start(I2C1, DS1307_I2C_ADDRESS, I2C_Direction_Transmitter); // 在 主模式(Master Mode) 中 開始準備發送
    I2C_write(I2C1, 0x00); // 寫入一個 byte 到 DS1307 模組
    
    I2C_write(I2C1, decToBcd(s)); // 寫入秒
    I2C_write(I2C1, decToBcd(mi)); // 寫入分
    I2C_write(I2C1, decToBcd(h)); // 寫入時
    I2C_write(I2C1, decToBcd(w)); // 寫入星期
    I2C_write(I2C1, decToBcd(d)); // 寫入日
    I2C_write(I2C1, decToBcd(m)); // 寫入月
    I2C_write(I2C1, decToBcd(y)); // 寫入年
    
    I2C_stop(I2C1); // 停止發送
}
 
// 取得時間
void getTime(){    
    
    I2C_start(I2C1, DS1307_I2C_ADDRESS, I2C_Direction_Transmitter); // 在 主發送 模式中 準備開始 發送
    I2C_write(I2C1, 0x00); // 寫入一個 byte 到 DS1307 模組   
    I2C_stop(I2C1); // 停止發送
    
    
    I2C_start(I2C1, DS1307_I2C_ADDRESS, I2C_Direction_Receiver); // 在 主接收 模式中 準備開始 接收
    
    s = bcdTodec(I2C_read_ack(I2C1)); // 取得秒
    mi = bcdTodec(I2C_read_ack(I2C1)); // 取得分
    h = bcdTodec(I2C_read_ack(I2C1)); // 取得時
    w = bcdTodec(I2C_read_ack(I2C1)); // 取得星期
    d = bcdTodec(I2C_read_ack(I2C1)); // 取得日
    m = bcdTodec(I2C_read_ack(I2C1)); // 取得月
    y = bcdTodec(I2C_read_ack(I2C1)) + 2000; // 取得年
    
    I2C_read_nack(I2C1); // 讀取一個 byet 後,就不再讀取後面一個 byte (停止傳輸)
}
 
// 顯示時間
void digitalClockDisplay(){
    char buff [] = "";
    
    sprintf (buff, "%d", y); // 將數字(年)轉成字串 (String)
    My_Usart3_Printf(buff);  // 輸出年
    My_Usart3_Printf("/");
    
    sprintf (buff, "%d", m); // 將數字(月)轉成字串 (String)
    My_Usart3_Printf(buff);  // 輸出月
    My_Usart3_Printf("/");
    
    sprintf (buff, "%d", d); // 將數字(日)轉成字串 (String)
    My_Usart3_Printf(buff);  // 輸出日
    My_Usart3_Printf(" ( ");
    
    sprintf (buff, "%d", w); // 將數字(星期)轉成字串 (String)
    My_Usart3_Printf(buff);  // 輸出星期
    My_Usart3_Printf(" ) ");
    
    sprintf (buff, "%d", h); // 將數字(時)轉成字串 (String)
    My_Usart3_Printf(buff);  // 輸出時
    My_Usart3_Printf(":");
    
    sprintf (buff, "%d", mi); // 將數字(分)轉成字串 (String)
    My_Usart3_Printf(buff);   // 輸出分
    My_Usart3_Printf(":");
    
    sprintf (buff, "%d", s); // 將數字(秒)轉成字串 (String)
    My_Usart3_Printf(buff);  // 輸出秒
    My_Usart3_Printf("\n");
}
 
int main(){
    
    Init_UART(); // 初始化 UART
    init_I2C1(); // 初始化 I²C
    
    setTime(13,10,17,4,23,4,0); // 設定時間:2013 年 10 月 17 日 星期4 23 點 4 分 0 秒
    
    My_Usart3_Printf(" Start : ");
    My_Usart3_Printf("--------------------------------------------------\n");
    
 
    while (1){       
        getTime(); // 取得時間
        digitalClockDisplay(); // 顯示時間 
        
        for(i=0; i<30000000; i++); // 延遲
    }
 
}
 

輸出結果:

ASD  


arrow
arrow
    全站熱搜

    黃彥霖 發表在 痞客邦 留言(1) 人氣()