1. 程式人生 > >STM32Cube MX 下IIC的配置與使用--GPIO模擬

STM32Cube MX 下IIC的配置與使用--GPIO模擬

本文介紹了在STM32下的IIC的基本使用方法,通過對板載具備IIC介面EEPROM的讀寫,完成對IIC驅動程式的測試。

硬體平臺:STM32F107VCT6開發板

軟體平臺:STM32Cube MX + MDK5.22

1. 進行STM32Cube MX的配置


配置PB6和PB7為輸出模式,同時配置了USART1進行串列埠除錯使用。然後生成工程。

2. 開啟工程,可以看到GPIO的初始化狀態


3. 模擬IIC驅動程式原始檔程式碼

/**
  * @file  iic_dup.c
  * @brief IIC上層程式
  * @par   date        version    author    remarks
  *        2016-03-21  v1.0       zbt       初次建立
  *
  */

/** 標頭檔案包含區 ------------------------------------------------ */
#include "iic_dup.h"

/** 私有巨集(型別定義) -------------------------------------------- */ 
#define IIC1_SCL(pin_status)        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, pin_status);
#define IIC1_SDA(pin_status)        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, pin_status);
#define IIC1_SCL_IS_HIGH()          (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) != GPIO_PIN_RESET)
#define IIC1_SDA_IS_HIGH()          (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7) != GPIO_PIN_RESET)

/** 私有變數 --------------------------------------------------- */


/** 外部變數 --------------------------------------------------- */

/** 私有函式原型 ----------------------------------------------- */
static void iic_delay(void);

/** 公有函式 --------------------------------------------------- */
/**
  * @brief  IIC啟動
  * @param  None
  * @retval None
  * @note   當SCL處於高電平狀態時,SDA出現一個下降沿
            即產生IIC啟動訊號
  */
void iic_start(void)
{
    IIC1_SCL(GPIO_PIN_SET);
    /** SDA產生一個下降沿 */
    IIC1_SDA(GPIO_PIN_SET);
    iic_delay(); 
    
    IIC1_SDA(GPIO_PIN_RESET);
    iic_delay(); 
    IIC1_SCL(GPIO_PIN_RESET);   /**< 拉低準備傳送資料 */
    iic_delay();   
}

/**
  * @brief  IIC停止
  * @param  None
  * @retval None
  * @note   當SCL處於高電平狀態時,SDA出現一個上升沿
            即產生IIC停止訊號
  */
void iic_stop(void)
{
    IIC1_SCL(GPIO_PIN_RESET);
    iic_delay();
    /** SDA產生一個上升沿 */
    IIC1_SDA(GPIO_PIN_RESET);
    iic_delay();
    
    IIC1_SCL(GPIO_PIN_SET);
    iic_delay();
    IIC1_SDA(GPIO_PIN_SET);
    iic_delay();
}

/**
  * @brief  IIC傳送1byte資料
  * @param  None
  * @retval None
  * @note   
  */
void iic_sendbyte(uint8_t byte)
{
    uint8_t i;
    
    /** 傳送一個位元組的高7位 */
    for (i = 0; i < 8; i++)
    {
        if (byte & 0x80)
        {
            IIC1_SDA(GPIO_PIN_SET);
        }
        else
        {
            IIC1_SDA(GPIO_PIN_RESET);
        }
        
        iic_delay();
        IIC1_SCL(GPIO_PIN_SET);
        iic_delay();
        IIC1_SCL(GPIO_PIN_RESET);
        
        if (i == 7)
        {
            IIC1_SDA(GPIO_PIN_SET);
        }
        
        byte <<= 1;
        iic_delay();
    }      
}

/**
  * @brief  IIC讀取1byte資料
  * @param  None
  * @retval None
  * @note             
  */
uint8_t iic_readbyte(void)
{
    uint8_t i;
    uint8_t recv_value = 0;
    
    IIC1_SDA(GPIO_PIN_SET);
    iic_delay();
    
    for (i = 0; i < 8; i++)
    {
        IIC1_SCL(GPIO_PIN_SET);
        iic_delay();
        recv_value <<= 1;
        if (IIC1_SDA_IS_HIGH())
        {
            recv_value |= 0x01;
        }
        else
        {
            recv_value &= ~0x01;
        }
        
        iic_delay();
        IIC1_SCL(GPIO_PIN_RESET);
    }
    
    return recv_value;
}

/**
  * @brief  IIC等待應答訊號
  * @param  None
  * @retval ack_status: 應答狀態,0表示應答,1表示裝置無響應
  */
uint8_t iic_wait_ack(void)
{
    uint8_t ack_status = 0;
    
    /** 在等待應答訊號之前,要釋放匯流排,即將SDA置位 */
    IIC1_SDA(GPIO_PIN_SET);
    iic_delay();
    IIC1_SCL(GPIO_PIN_SET);
    iic_delay();
    
    if (IIC1_SDA_IS_HIGH())
    {    
        ack_status = 1;
        iic_stop();
    }
    else
    {
        ack_status = 0;
    }
    
    IIC1_SCL(GPIO_PIN_RESET);
    iic_delay();
    
    return ack_status;
}

/**
  * @brief  主機(主控制器)產生應答訊號
  * @param  None
  * @retval None
  */
void iic_ack(void)
{
    IIC1_SDA(GPIO_PIN_RESET);
    iic_delay();
    
    IIC1_SCL(GPIO_PIN_SET);
    iic_delay();
    IIC1_SCL(GPIO_PIN_RESET);
    iic_delay();
    
    IIC1_SDA(GPIO_PIN_SET);
}

/**
  * @brief  主機(主控制器)產生不應答訊號
  * @param  None
  * @retval None
  */
void iic_nack(void)
{
    IIC1_SDA(GPIO_PIN_SET);
    iic_delay();
    
    IIC1_SCL(GPIO_PIN_SET);
    iic_delay();
    IIC1_SCL(GPIO_PIN_RESET);
    iic_delay();
}

/**
  * @brief  檢測IIC總線上的裝置狀態
  * @param  device_addr: 從機裝置地址 
  * @retval ack_status: 0 (正常)or 1(異常)
  * @note   主機發送裝置地址等待從機應答,若有從機正確的應答訊號
            則表明IIC總線上掛接了裝置,否則表示IIC總線上未檢測到
            裝置
  */
uint8_t iic_check_device_status(uint8_t device_addr)
{
    uint8_t ack_status;
    
    if (IIC1_SCL_IS_HIGH() && IIC1_SDA_IS_HIGH())
    {
        iic_start();
        
        iic_sendbyte(device_addr | IIC_WRITE);
        ack_status = iic_wait_ack();

        iic_stop();
        
        return ack_status;
    }
    
    return 1;
}

/** 私有函式 --------------------------------------------------- */
/**
  * @brief  用於模擬IIC時的簡單延時
  * @param  None
  * @retval None
  */
static void iic_delay(void)
{
    uint8_t i = 0;
    uint8_t delay = 5;
    
    while (delay--)
    {
        i = 10;
        while (i--);
    }
}

4. AT24C02部分驅動程式碼

/**
  * @file  at24c02.c
  * @brief at24c02驅動程式
  * @par   date        version    author    remarks
  *        2016-03-21  v1.0       zbt       初次建立
  *
  */

/** 標頭檔案包含區 ------------------------------------------------ */
#include "at24c02.h"
#include "iic_dup.h"

/** 私有巨集(型別定義) -------------------------------------------- */ 
#define AT24C02_DEVICE_ADDR         0xA0
#define AT24C02_PAGE_SIZE           8
#define AT24C02_MEM_SIZE            256
#define AT24C02_ADDR_BYTE           1

/** 私有變數 --------------------------------------------------- */
uint8_t test_buffer[AT24C02_MEM_SIZE];

/** 外部變數 --------------------------------------------------- */

/** 私有函式原型 ----------------------------------------------- */
//static void AT24C02_ack(void);
static void AT24C02_error_handle(void);
static void AT24C02_read_test(void);
static void AT24C02_write_test(void);
static void AT24C02_erase_test(void);

/** 公有函式 --------------------------------------------------- */
/**
  * @brief  AT24C02與主控制器的IIC通訊測試程式碼
  * @param  None
  * @retval None
  */
void AT24C02_iic_test(void)
{
    iic_stop();     /**< 必須先復位IIC總線上的裝置到待機模式 */
    HAL_Delay(10);
    
    /** 檢測總線上是否掛接了IIC裝置(此處為AT24C02) */
    if (iic_check_device_status(AT24C02_DEVICE_ADDR) == 0)
    {
        printf("iic device exists\n");
    }
    else
    {
        printf("no iic device exists\n");
    }
    
    AT24C02_write_test();
    HAL_Delay(5);
    AT24C02_read_test();
    HAL_Delay(5);
    AT24C02_erase_test();
}

/**
  * @brief  從AT24C02中讀取資料
  * @param  read_data: 讀取到的資料
  * @param  start_addr: 讀取資料的起始地址
  * @param  data_length: 資料的長度
  * @retval None
  */
void AT24C02_read_data(uint8_t *read_data, uint16_t start_addr, uint16_t data_length)
{
    uint16_t i;
    
    iic_start();
    iic_sendbyte(AT24C02_DEVICE_ADDR | IIC_WRITE);
//    AT24C02_ack();
    if (iic_wait_ack() != 0)
    {
        AT24C02_error_handle();
        printf("first read error\r\n");
    }
    
    if (AT24C02_ADDR_BYTE == 1)
    {
        iic_sendbyte((uint8_t)start_addr & 0xff);
//        AT24C02_ack();
        if (iic_wait_ack() != 0)
        {
            AT24C02_error_handle();
            printf("addr byte error\r\n");
        }
    }
    
    iic_start();
    iic_sendbyte(AT24C02_DEVICE_ADDR | IIC_READ);
//    AT24C02_ack();
    if (iic_wait_ack() != 0)
    {
        AT24C02_error_handle();
        printf("read data error\r\n");
    }
    
    for (i = 0; i < data_length; i++)
    {
        read_data[i] = iic_readbyte();
        
        if (i != data_length - 1)
        {
            iic_ack();      /**< 讀完非最後一個位元組後, 產生應答訊號 */
        }
        else
        {
            iic_nack();     /**< 最後一個位元組讀完後 產生非應答訊號 */
        }
//        printf("read data is %d\n", read_data[i]);  /**< 除錯程式碼 */
    }
    
    iic_stop();
}

/**
  * @brief  通過IIC向AT24C02寫資料
  * @param  write_data:  要寫入AT24C02的資料指標
  * @param  start_addr:  要寫入AT24C02的起始地址
  * @param  data_length: 要寫入AT24C02的資料長度
  * @retval None
  */
void AT24C02_write_data(uint8_t *write_data, uint16_t start_addr, uint16_t data_length)
{
    uint16_t i, j;
    uint16_t start_addr_dup;
    
    start_addr_dup = start_addr;
    for (i = 0; i < data_length; i++)
    {
        
        if ((i == 0) || (start_addr_dup & (AT24C02_PAGE_SIZE - 1)) == 0)
        {
            iic_stop();
            
            for (j = 0; j < 2000; j++)
            {
                iic_start();
                iic_sendbyte(AT24C02_DEVICE_ADDR | IIC_WRITE);
                
                if (iic_wait_ack() == 0)
                {
                    break;
                }
            }
            if (j >= 2000)
            {
                printf("j = 1000\r\n");
                AT24C02_error_handle();
            }
            
            if (AT24C02_ADDR_BYTE == 1)
            {
                iic_sendbyte((uint8_t)start_addr_dup & 0xff);
//                AT24C02_ack();
                if (iic_wait_ack() != 0)
                {
                    AT24C02_error_handle();
                    printf("addr_byte wrong\r\n");
                }
            }
        }
        
        iic_sendbyte(write_data[i]);
//        AT24C02_ack();
        if (iic_wait_ack() != 0)
        {
            AT24C02_error_handle();
            printf("write failed\r\n");
        }
        
//        printf("write_data is %d \n", write_data[i]);    /**< 除錯程式碼 */ 
        start_addr_dup++;
    }
    
    iic_stop();
}

/** 私有函式 --------------------------------------------------- */
/** 以下為測試用程式 ------------------------------------------- */
/**
  * @brief  AT24C02讀取資料測試
  * @param  None
  * @retval None
  */
static void AT24C02_read_test(void)
{
    uint16_t i;
    
    AT24C02_read_data(test_buffer, 0, (AT24C02_MEM_SIZE % 10));
    
    printf("read data is:\n");
    for (i = 0; i < (AT24C02_MEM_SIZE % 10); i++)
    {
        printf("%d ", test_buffer[i]);
    }
    
    printf("\r\nread test ok\r\n");
}

/**
  * @brief  AT24C02寫資料測試
  * @param  None
  * @retval None
  */
static void AT24C02_write_test(void)
{
    uint16_t i;
    
    for (i = 0; i < (AT24C02_MEM_SIZE % 10); i++)
    {
        test_buffer[i] = i;
    }
    
    AT24C02_write_data(test_buffer, 0, (AT24C02_MEM_SIZE % 10));
    
    printf("write data is:\n");
    for (i = 0; i < (AT24C02_MEM_SIZE % 10); i++)
    {
        printf("%d ", test_buffer[i]);
    }
    
    printf("\r\nwrite test ok\r\n");
}

/**
  * @brief  AT24C02擦除資料測試
  * @param  None
  * @retval None
  */
static void AT24C02_erase_test(void)
{
    uint16_t i;
    
    for (i = 0; i < (AT24C02_MEM_SIZE % 10); i++)
    {
        test_buffer[i] = 0xff;
    }
    
    AT24C02_write_data(test_buffer, 0, (AT24C02_MEM_SIZE % 10));
    
    printf("erase value is: \n");
    for (i = 0; i < (AT24C02_MEM_SIZE % 10); i++)
    {
        printf("%d ", test_buffer[i]);
    }
    
    printf("\r\nerase test ok\r\n");
}
/** 以上為測試用程式 ------------------------------------------- */

/**
  * @brief  AT24C02應答錯誤處理程式
  * @param  None
  * @retval None
  */
static void AT24C02_error_handle(void)
{
    iic_stop();
//    printf("At24C02 read failed\r\n");   /**< 除錯用 */
}

//static void AT24C02_ack(void)
//{
//    if (iic_wait_ack() != 0)
//    {
//        AT24C02_error_handle();
//    }
//}



5. 在主函式中新增 AT24C02_iic_test(); 進行讀寫測試成功。

相關推薦

STM32Cube MX IIC配置使用--GPIO模擬

本文介紹了在STM32下的IIC的基本使用方法,通過對板載具備IIC介面EEPROM的讀寫,完成對IIC驅動程式的測試。 硬體平臺:STM32F107VCT6開發板 軟體平臺:STM32Cube MX + MDK5.22 1. 進行STM32Cube MX的配置 配置P

win7 jenkins 配置使用

錯誤 新版 一個 pan 其中 line 用戶註冊 安裝路徑 輸出 一、Jenkins的配置 1. 下載地址: Jenkins的官方網站:http://jenkins-ci.org/ 目前最新版本的Windows版:https://jenkins.io/download/t

apachehttps配置優化效能具體操作

宣告:以下操作路徑及 httpd.conf檔案與原始檔案有所區別,博主採用的httpd.conf引入其他配置檔案進行分專案管理,大體操作類似 對於nginx參考騰訊實踐-騰訊HTTPS效能優化實踐 *可以忽略此段 -http.txt 檔案為80埠配置檔案修改後綴為conf,重啟apa

ubuntu16.04vim配置自動補全

開啟終端,輸入vim ~/.vimrc 將以下內容儲存 set nocompatible "去掉有關vim一致性模式,避免以前版本的一些bug和侷限. set mouse=a "滑鼠可任意移動 set number "顯示行號. set ruler "顯示當

Opencv 2.4.9在Ubuntu配置安裝

一、依賴包安裝        1.  build-essential 軟體包,為編譯程式提供必需軟體包的列表資訊,這樣軟體包才知道標頭檔案、庫函式在哪裡。還會下載依賴的軟體包,安裝gcc/g++/gdb/make 等基本程式設計工具,最後才組成一個開發環境。 sudo a

【Docker】Docker學習筆記(1)-Windows配置安裝

第一次接觸Docker是15年夏天,那時候在七牛學習Go語言,周圍的大牛們突然提到Docker容器這個東西,而且非常火爆~直到一年多後才想起來要學習一下Docker到底是個什麼東西(我真是怠惰啊),廢話不多說,開始正文。 配置Hyper-V環境並安裝Doc

配置核心gpio模擬spi時序的方法

假如你現在有一份基於核心介面SPI的驅動,但是現在你的硬體已經沒有多餘的SPI介面了。怎麼辦?難道我們需要重新寫驅動嗎,像微控制器一樣去操作IO的高低來符合時序。那麼你的工作量就加大了。其實,linux核心已經寫好了模擬SPI時序,你只需要配置好。就可以使用了。下面分享一下

LinuxNFS配置tftp配置

1. NFS配置 vi /etc/export 加入所需要共享目錄。例如: /home/liukang/workship 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check) 修改完畢後,執行 #exportfs

Window2003ss配置連線

這個,ss是啥? 能搜到這篇文章的同學我就不解釋了 這個網上這方面的教程也很多 最近我搜了一下,發現很多原來的文章都不見了。。。好吧 我對win體系的伺服器配置也沒有多少經驗 寫寫自己實際操作的經驗吧 這個,要想那個啥,你得先有一個 V P S

網絡硬件設備配置管理(CCNA)

網絡 硬件 cisco ccna 點擊下載:網絡硬件設備配置與管理(CCNA)下本文出自 “飛奔的魚兒” 博客,請務必保留此出處http://feiyuer.blog.51cto.com/6967044/1931155網絡硬件設備配置與管理(CCNA)下

windowMongoDB的配置安裝

ets ann sock important sof hot sys support 環境 前言 MongoDB 是一個基於分布式文件存儲的數據庫。由C++語言編寫,支持Windows,Linux,OSX,Solaris等平臺,默認端口為27017,是一個效率非常高的no

linuxLAMP安裝配置

函數 rri osi ase live ins php expose share 安裝 一. Apache 安裝 yum install -y httpd啟動 /etc/init.d/httpd start備註:Apache啟動之後會提示錯誤: 正在啟動http

Linux安裝Nginx配置

目錄 openssl oct pan yum安裝 usr 負載均衡 官方 err 一,安裝GCC yum安裝gcc-c ++ -y 二,安裝nginx的所需要的依賴庫 yum -y安裝zlib-devel openssl-devel pcre-devel

Redis在Linux的安裝配置

conf eas etc 下載 127.0.0.1 基於內存 最新 ansi lin Redis是一個開源的使用ANSI C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value數據庫,並提供多種語言的API。 Redis是 NoSQL技術陣營中的一員。 說到

linuxFTP安裝配置

linux ftp pure-ftpdcd /usr/local/src/wget http://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.42.tar.bz2 (下載pureftp源碼包)tar jxvf pure-f

linuxrsync安裝配置

linux rsync rsync (同步數據,支持增量備份)使用方法:rsync -av 192.168.31.182:/tmp/1.txt /tmp/ (將服務器192.168.31.182中tmp文件夾下的1.txt文件拷貝到本機的tmp目錄下)rsync -av /tmp/1.tx

VMware網絡模式配置IP地址無法正常獲取及解決方案

什麽 應該 任務 互連 但我 intern 資料 for 互聯 目錄一 網絡配置中出現的錯誤及解決方案二 VMware下網絡配置的三種模式簡介 1、橋接模式(Bridged) 2、網絡地址轉化模式(NAT) 3、僅主機模式(host-only)一 網

windowsPostgreSQL 安裝配置

this 開始 ror scripting ping 存儲 install driver 選擇 下載地址 https://www.postgresql.org/download/ Download the installer certified by Enterpris

centos7NFS使用配置

nfs linuxnfs centosnfs NFS是Network File System的縮寫,即網絡文件系統。客戶端通過掛載的方式將NFS服務器端共享的數據目錄掛載到本地目錄下。一、NFS的工作流程1、由程序在NFS客戶端發起存取文件的請求,客戶端本地的RPC(rpcbind)服務會

ubuntu16.04hive安裝配置

cep ted dir mave value usr ubunt java HA 下載 wget http://mirrors.hust.edu.cn/apache/hive/hive-2.3.2/apache-hive-2.3.2-bin.tar.gz 解壓到指定