/*! * COPYRIGHT NOTICE * Copyright (c) 2013,山外科技 * All rights reserved. * 技術討論:山外論壇 http://www.vcan123.com * * 除注明出處外,以下所有內容版權均屬山外科技所有,未經允許,不得用於商業用途, * 修改內容時必須保留山外科技的版權聲明。 * * @file VCAN_SCCB.c * @brief OV攝像頭配置總線SCCB函數庫 * @author 山外科技 * @version v5.0 * @date 2013-09-01 */ #include "common.h" #include "MK60_gpio.h" #include "VCAN_SCCB.h" static void SCCB_delay(uint16 i); /*! * @brief SCCB延遲函數 * @param time 延時時間 * @since v5.0 */ static void SCCB_delay(volatile uint16 time) { while(time) { time--; } } /*! * @brief SCCB管腳配置 * @since v5.0 */ void SCCB_GPIO_init(void) { gpio_init (SCCB_SCL, GPO, 1); //初始化SCL gpio_init (SCCB_SDA, GPO, 1); //初始化SDA port_init_NoALT(SCCB_SCL,ODO | PULLUP); port_init_NoALT(SCCB_SDA,ODO | PULLUP); } /*! * @brief SCCB起始信號 * @since v5.0 */ static uint8 SCCB_Start(void) { SDA_H(); SCL_H(); SCCB_DELAY(); SDA_DDR_IN(); if(!SDA_IN()) { SDA_DDR_OUT(); return 0; /* SDA線為低電平則總線忙,退出 */ } SDA_DDR_OUT(); SDA_L(); SCCB_DELAY(); SCL_L(); if(SDA_IN()) { SDA_DDR_OUT(); return 0; /* SDA線為高電平則總線出錯,退出 */ } //SDA_DDR_OUT(); //SDA_L(); //SCCB_delay(); return 1; } /*! * @brief SCCB停止信號 * @since v5.0 */ static void SCCB_Stop(void) { SCL_L(); //SCCB_DELAY(); SDA_L(); SCCB_DELAY(); SCL_H(); SCCB_DELAY(); SDA_H(); SCCB_DELAY(); } /*! * @brief SCCB應答信號 * @since v5.0 */ static void SCCB_Ack(void) { SCL_L(); SCCB_DELAY(); SDA_L(); SCCB_DELAY(); SCL_H(); SCCB_DELAY(); SCL_L(); SCCB_DELAY(); } /*! * @brief SCCB無應答信號 * @since v5.0 */ static void SCCB_NoAck(void) { SCL_L(); SCCB_DELAY(); SDA_H(); SCCB_DELAY(); SCL_H(); SCCB_DELAY(); SCL_L(); SCCB_DELAY(); } /*! * @brief SCCB 等待應答 * @return 應答結果(0表示無應答,1表示有應答) * @since v5.0 */ static int SCCB_WaitAck(void) { SCL_L(); //SDA_H(); SDA_DDR_IN(); SCCB_DELAY(); SCL_H(); SCCB_DELAY(); if(SDA_IN()) //應答為高電平,異常,通信失敗 { SDA_DDR_OUT(); SCL_L(); return 0; } SDA_DDR_OUT(); SCL_L(); return 1; } /*! * @brief SCCB 發送的數據 * @param SendByte 需要發送的數據 * @since v5.0 */ static void SCCB_SendByte(uint8 SendByte) { uint8 i = 8; while(i--) { if(SendByte & 0x80) //SDA 輸出數據 { SDA_H(); } else { SDA_L(); } SendByte <<= 1; SCCB_DELAY(); SCL_H(); //SCL 拉高,采集信號 SCCB_DELAY(); SCL_L(); //SCL 時鍾線拉低 //SCCB_DELAY(); } //SCL_L(); } /*! * @brief 接收SCCB總線的數據 * @return 接收到的數據 * @since v5.0 */ static int SCCB_ReceiveByte(void) { uint8 i = 8; uint8 ReceiveByte = 0; //SDA_H(); //SCCB_DELAY(); SDA_DDR_IN(); while(i--) { ReceiveByte <<= 1; SCL_L(); SCCB_DELAY(); SCL_H(); SCCB_DELAY(); if(SDA_IN()) { ReceiveByte |= 0x01; } } SDA_DDR_OUT(); SCL_L(); return ReceiveByte; } /***************************************************************************************** * 函數名:SCCB_WriteByte * 描述 :寫一字節數據 * 輸入 :- WriteAddress: 待寫入地址 - SendByte: 待寫入數據 - DeviceAddress: 器件類型 * 輸出 :返回為:=1成功寫入,=0失敗 * 注意 :無 *****************************************************************************************/ static int SCCB_WriteByte_one( uint16 WriteAddress , uint8 SendByte ); int SCCB_WriteByte( uint16 WriteAddress , uint8 SendByte ) //考慮到用sccb的管腳模擬,比較容易失敗,因此多試幾次 { uint8 i = 0; while( 0 == SCCB_WriteByte_one ( WriteAddress, SendByte ) ) { i++; if(i == 20) { return 0 ; } } return 1; } int SCCB_WriteByte_one( uint16 WriteAddress , uint8 SendByte ) { if(!SCCB_Start()) { return 0; } SCCB_SendByte( DEV_ADR ); /* 器件地址 */ if( !SCCB_WaitAck() ) { SCCB_Stop(); return 0; } SCCB_SendByte((uint8)(WriteAddress & 0x00FF)); /* 設置低起始地址 */ SCCB_WaitAck(); SCCB_SendByte(SendByte); SCCB_WaitAck(); SCCB_Stop(); return 1; } /****************************************************************************************************************** * 函數名:SCCB_ReadByte * 描述 :讀取一串數據 * 輸入 :- pBuffer: 存放讀出數據 - length: 待讀出長度 - ReadAddress: 待讀出地址 - DeviceAddress: 器件類型 * 輸出 :返回為:=1成功讀入,=0失敗 * 注意 :無 **********************************************************************************************************************/ static int SCCB_ReadByte_one(uint8 *pBuffer, uint16 length, uint8 ReadAddress); int SCCB_ReadByte(uint8 *pBuffer, uint16 length, uint8 ReadAddress) { uint8 i = 0; while( 0 == SCCB_ReadByte_one(pBuffer, length, ReadAddress) ) { i++; if(i == 30) { return 0 ; } } return 1; } int SCCB_ReadByte_one(uint8 *pBuffer, uint16 length, uint8 ReadAddress) { if(!SCCB_Start()) { return 0; } SCCB_SendByte( DEV_ADR ); /* 器件地址 */ if( !SCCB_WaitAck() ) { SCCB_Stop(); return 0; } SCCB_SendByte( ReadAddress ); /* 設置低起始地址 */ SCCB_WaitAck(); SCCB_Stop(); if(!SCCB_Start()) { return 0; } SCCB_SendByte( DEV_ADR + 1 ); /* 器件地址 */ if(!SCCB_WaitAck()) { SCCB_Stop(); return 0; } while(length) { *pBuffer = SCCB_ReceiveByte(); if(length == 1) { SCCB_NoAck(); } else { SCCB_Ack(); } pBuffer++; length--; } SCCB_Stop(); return 1; }