IIC也是非常常用的一个外设,虽然速度不快,但胜在只需要两个管脚就搞定,还有应答机制。 细想想IIC像极了女票,你回到家,女友给你声问候(起始信号),提到你的名字(addr地址)等你回应,然后和你倒一段苦水,再等你回应,再接着倒,再等你回应,如果她说完之前不理她了,一会她就不高兴了(应答错误)然后和你说了声不理你了(停止位)然后就dy外放去了,有时候交流不畅,女友生气了哄起来也头痛(总线死锁)。所以还是纸片人好。
后面需要用到矩阵按键,又不想mcu太累,还是招个专门的ic来负责吧!tb市场转了一圈,最后谈妥了沁恒的CH450,兼容I2C,最高2M,这价格还要啥自行车了。还有个国产的xxx来着uart接口,运费10元,果断推掉。
下面来看下具体代码USER下新建drv_i2c.c和drv_i2c.h
-
-
-
-
- #include "at32f4xx.h"
- #include "drv_i2c.h"
- #include "at32_board.h"
- #include <rthw.h>
- #include <rtthread.h>
-
- /**
- * [url=home.php?mod=space&uid=159083]@brief[/url] I2C Timeout definition
- */
- #define I2C_TIMEOUT_FLAG ((uint32_t)35)
- #define I2C_TIMEOUT_ADDR_SLAVE ((uint32_t)10000)
- #define I2C_TIMEOUT_BUSY_FLAG ((uint32_t)10000)
-
- /**
- * @brief I2C Event check flag definition
- */
- #define I2C_EVT_CHECK_NONE ((uint32_t)0x00000000)
- #define I2C_EVT_CHECK_ACKFAIL ((uint32_t)0x00000001)
- #define I2C_EVT_CHECK_STOP ((uint32_t)0x00000002)
-
- /**
- * @brief us delay used by the I2C.
- * @param us: delay x us.
- * @retval None
- */
- void I2C_Delay(uint32_t us)
- {
- us *= 300;
- while(us!=0){
- us--;
- }
- }
-
- /** @brief Clears the I2C ADDR pending flag.
- * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
- * @retval None
- */
- void I2C_ClearADDRFlag(I2C_Type* I2Cx)
- {
- __IO uint32_t tmpreg;
-
- tmpreg = I2Cx->STS1;
-
- tmpreg = I2Cx->STS2;
- }
-
-
- /** @brief Clears the I2C STOPF pending flag.
- * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
- * @retval None
- */
- void I2C_ClearSTOPFlag(I2C_Type* I2Cx)
- {
- __IO uint32_t tmpreg;
-
- tmpreg = I2Cx->STS1;
-
- tmpreg = I2Cx->CTRL1 |= I2C_CTRL1_PEN;
- }
-
- /**
- * @brief This function handles I2C Communication Timeout.
- * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
- * @param Flag: specifies the I2C flag to check.
- * @param Status: The new Flag status (SET or RESET).
- * @param Timeout Timeout duration.
- * @retval I2C status.
- */
- static I2C_StatusType I2C_WaitOnFlagUntilTimeout(I2C_Type* I2Cx, uint32_t Flag, FlagStatus Status, uint32_t EventCheck, uint32_t Timeout)
- {
-
- Timeout *= 100;
-
- while(I2C_GetFlagStatus(I2Cx, Flag) == Status)
- {
-
- if(EventCheck & I2C_EVT_CHECK_ACKFAIL)
- {
- if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_ACKFAIL) == SET)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
-
- I2C_ClearFlag(I2Cx, I2C_FLAG_ACKFAIL);
-
- return I2C_ERROR;
- }
- }
-
-
- if(EventCheck & I2C_EVT_CHECK_STOP)
- {
- if(I2C_GetFlagStatus(I2Cx, I2C_FLAG_STOPF) == SET)
- {
-
- I2C_ClearSTOPFlag(I2Cx);
-
- return I2C_ERROR;
- }
- }
-
-
- I2C_Delay(10);
-
-
- if((Timeout--) == 0)
- {
- return I2C_TIMEOUT;
- }
- }
-
- return I2C_OK;
- }
-
-
- /**
- * @brief I2C初始化
- * @param None
- * @retval None
- */
- void I2Cx_Init(void)
- {
- GPIO_InitType GPIO_InitStructure;
- I2C_InitType I2C_InitStructure;
-
-
- RCC_AHBPeriphClockCmd(I2C_GPIO_CLK , ENABLE);
-
- RCC_APB1PeriphClockCmd(I2C_CLK, ENABLE);
-
-
- GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
- GPIO_InitStructure.GPIO_OutType = GPIO_OutType_OD;
- GPIO_InitStructure.GPIO_Pull = GPIO_Pull_NOPULL;
-
- GPIO_InitStructure.GPIO_Pins = I2C_SCL_PIN;
- GPIO_Init(I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
-
-
- GPIO_InitStructure.GPIO_Pins = I2C_SDA_PIN;
- GPIO_Init(I2C_SDA_GPIO_PORT, &GPIO_InitStructure);
-
-
- GPIO_PinAFConfig(I2C_SCL_GPIO_PORT, I2C_SCL_GPIO_PinsSource, I2C_SCL_GPIO_GPIO_AF);
- GPIO_PinAFConfig(I2C_SDA_GPIO_PORT, I2C_SDA_GPIO_PinsSource, I2C_SDA_GPIO_GPIO_AF);
-
-
- I2C_InitStructure.I2C_Mode = I2C_Mode_I2CDevice;
- I2C_InitStructure.I2C_FmDutyCycle = I2C_FmDutyCycle_2_1;
- I2C_InitStructure.I2C_OwnAddr1 = I2C_SLAVE_ADDRESS7;
- I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
- I2C_InitStructure.I2C_AddrMode = I2C_AddrMode_7bit;
- I2C_InitStructure.I2C_BitRate = I2C_SPEED;
-
-
- I2C_Init(I2C_PORT, &I2C_InitStructure);
-
-
- I2C_Cmd(I2C_PORT, ENABLE);
- }
-
- /**
- * @brief Receives in master mode an amount of data in blocking mode.
- * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
- * @param DevAddress Target device address.
- * @param pData Pointer to data buffer.
- * @param Size Amount of data to be sent.
- * @param Timeout Timeout duration.
- * @retval I2C status.
- */
- I2C_StatusType I2C_Receive(I2C_Type* I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
- {
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BUSYF, SET, I2C_EVT_CHECK_NONE, I2C_TIMEOUT_BUSY_FLAG) != I2C_OK)
- {
- return I2C_ERROR_STEP_1;
- }
-
-
- I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);
-
-
- I2C_AcknowledgeConfig(I2Cx, ENABLE);
-
-
- I2C_GenerateSTART(I2Cx, ENABLE);
-
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_STARTF, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_2;
- }
-
-
- I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Receive);
-
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_ADDRF, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_3;
- }
-
- if(Size == 1)
- {
-
- I2C_AcknowledgeConfig(I2Cx, DISABLE);
-
-
- I2C_ClearADDRFlag(I2Cx);
-
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
- }
- else if(Size == 2)
- {
-
- I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Next);
-
-
- I2C_AcknowledgeConfig(I2Cx, DISABLE);
-
-
- I2C_ClearADDRFlag(I2Cx);
- }
- else
- {
-
- I2C_AcknowledgeConfig(I2Cx, ENABLE);
-
-
- I2C_ClearADDRFlag(I2Cx);
- }
-
- while(Size > 0)
- {
- if(Size <= 3)
- {
-
- if(Size == 1)
- {
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_RDNE, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_4;
- }
-
-
- (*pData++) = I2C_ReceiveData(I2Cx);
- Size--;
- }
-
- else if(Size == 2)
- {
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BTFF, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_5;
- }
-
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
-
- (*pData++) = I2C_ReceiveData(I2Cx);
- Size--;
-
-
- (*pData++) = I2C_ReceiveData(I2Cx);
- Size--;
- }
-
- else
- {
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BTFF, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_6;
- }
-
-
- I2C_AcknowledgeConfig(I2Cx, DISABLE);
-
-
- (*pData++) = I2C_ReceiveData(I2Cx);
- Size--;
-
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BTFF, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_7;
- }
-
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
-
- (*pData++) = I2C_ReceiveData(I2Cx);
- Size--;
-
-
- (*pData++) = I2C_ReceiveData(I2Cx);
- Size--;
- }
- }
- else
- {
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_RDNE, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_8;
- }
-
-
- (*pData++) = I2C_ReceiveData(I2Cx);
- Size--;
- }
- }
-
- return I2C_OK;
- }
-
- /**
- * @brief Transmits in master mode an amount of data in blocking mode.
- * @param I2Cx: where x can be 1, 2 or 3 to select the I2C peripheral.
- * @param DevAddress Target device address.
- * @param pData Pointer to data buffer.
- * @param Size Amount of data to be sent.
- * @param Timeout Timeout duration.
- * @retval I2C status.
- */
- I2C_StatusType I2C_Transmit(I2C_Type* I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout)
- {
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BUSYF, SET, I2C_EVT_CHECK_NONE, I2C_TIMEOUT_BUSY_FLAG) != I2C_OK)
- {
- return I2C_ERROR_STEP_1;
- }
-
-
- I2C_NACKPositionConfig(I2Cx, I2C_NACKPosition_Current);
-
-
- I2C_GenerateSTART(I2Cx, ENABLE);
-
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_STARTF, RESET, I2C_EVT_CHECK_NONE, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_2;
- }
-
-
- I2C_Send7bitAddress(I2Cx, DevAddress, I2C_Direction_Transmit);
-
-
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_ADDRF, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_3;
- }
-
-
- I2C_ClearADDRFlag(I2Cx);
-
- while(Size > 0)
- {
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_TDE, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_4;
- }
-
-
- I2C_SendData(I2Cx, (*pData++));
- Size--;
- }
-
-
- if(I2C_WaitOnFlagUntilTimeout(I2Cx, I2C_FLAG_BTFF, RESET, I2C_EVT_CHECK_ACKFAIL, Timeout) != I2C_OK)
- {
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_ERROR_STEP_5;
- }
-
-
- I2C_GenerateSTOP(I2Cx, ENABLE);
-
- return I2C_OK;
- }
-
- /**
- * @}
- */
-
- /**
- * @}
- */
-
-
懒得写,直接拷的例程中的代码,封装了发送和接收函数(有点想念HAL库了)
-
-
- #ifndef __AT32F4XX_I2C_EX_H
- #define __AT32F4XX_I2C_EX_H
-
-
- #include "at32f4xx.h"
-
- /**
- * @brief I2C Status structures definition
- */
- typedef enum
- {
- I2C_OK = 0,
-
- I2C_ERROR_STEP_1 = 1,
- I2C_ERROR_STEP_2 = 2,
- I2C_ERROR_STEP_3 = 3,
- I2C_ERROR_STEP_4 = 4,
- I2C_ERROR_STEP_5 = 5,
- I2C_ERROR_STEP_6 = 6,
- I2C_ERROR_STEP_7 = 7,
- I2C_ERROR_STEP_8 = 8,
- I2C_ERROR_STEP_9 = 9,
- I2C_ERROR_STEP_10 = 10,
- I2C_ERROR_STEP_11 = 11,
- I2C_ERROR_STEP_12 = 12,
-
- I2C_BUSY = 100,
- I2C_TIMEOUT = 101,
- I2C_ERROR = 102,
-
- } I2C_StatusType;
-
-
- /**
- * @}
- */
-
-
-
- /** @defgroup I2C_Exported_Constants I2C Exported Constants
- * @{
- */
-
- /**
- * @brief I2C Parameter definition
- */
- #define I2C_SPEED 100000
- #define I2C_SLAVE_ADDRESS7 0xB0
- #define I2C_EEAddress 0xB0
-
- /**
- * @brief I2C Interface pins
- */
- #define I2C_PORT I2C1
- #define I2C_CLK RCC_APB1PERIPH_I2C1
- #define I2C_SCL_PIN GPIO_Pins_8
- #define I2C_SCL_GPIO_PORT GPIOB
- #define I2C_GPIO_CLK RCC_AHBPERIPH_GPIOB
- #define I2C_SCL_GPIO_PinsSource GPIO_PinsSource8
- #define I2C_SCL_GPIO_GPIO_AF GPIO_AF_1
-
- #define I2C_SDA_PIN GPIO_Pins_9
- #define I2C_SDA_GPIO_PORT GPIOB
- #define I2C_SDA_GPIO_PinsSource GPIO_PinsSource9
- #define I2C_SDA_GPIO_GPIO_AF GPIO_AF_1
-
- /**
- * @}
- */
-
-
-
- /** @defgroup I2C_Exported_Macros I2C Exported Macros
- * @{
- */
- #define MASTER_BOARD
- /**
- * @}
- */
-
-
-
- /** @addtogroup I2C_Exported_Functions
- * @{
- */
-
-
- void I2Cx_Init(void);
-
- I2C_StatusType I2C_Receive (I2C_Type* I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
- I2C_StatusType I2C_Transmit(I2C_Type* I2Cx, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
-
-
- /**
- * @}
- */
-
- #endif
-
-
还要新建CH450.c和。h文件来写ch450的驱动
- #include "CH450.h"
- #include "at32f4xx.h"
- #include "drv_i2c.h"
- #include <rtthread.h>
-
- I2C_StatusType I2C_Status;
- void CH450_Write(uint8_t cmd)
- {
- I2C_Status = I2C_Transmit(I2C_PORT, CH450_Write_ADDR, &cmd, 1, 1000);
- rt_kprintf("I2C_Status:%d\r\n",I2C_Status);
- }
-
- unsigned char CH450_Read(void)
- {
- unsigned char keycode;
- I2C_Receive(I2C_PORT, CH450_Read_ADDR, &keycode, 1, 1000);
- return(keycode);
- }
-
- void CH450_Init(void)
- {
- CH450_Write(CH450_SYSON2);
- }
- #ifndef __CH450_H
- #define __CH450_H
- #include "stdint.h"
-
-
-
-
- #define CH450_SYSOFF 0x00 // 关闭显示、关闭键盘
- #define CH450_SYSON1 0x01 // 开启显示
- #define CH450_SYSON2 0x03 // 开启显示、键盘
- #define CH450_SYSON3 0x22 // 关闭显示、开启键盘
- #define CH450_GET_KEY 0x0700 // 获取按键,返回按键代码
- #define CH450_DIG2 0x1200 // 数码管位2显示,需另加8位数据
- #define CH450_DIG3 0x1300 // 数码管位3显示,需另加8位数据
- #define CH450_DIG4 0x1400 // 数码管位4显示,需另加8位数据
- #define CH450_DIG5 0x1500 // 数码管位5显示,需另加8位数据
- #define CH450_DIG6 0x1600 // 数码管位6显示,需另加8位数据
- #define CH450_DIG7 0x1700 // 数码管位7显示,需另加8位数据
-
-
- #define CH450_Write_ADDR 0x48 // 设置命令地址
- #define CH450_Read_ADDR 0x4F // 读取按键地址
- #define CH450_DIG2_ADDR 0x64 // DIG2字命令
- #define CH450_DIG3_ADDR 0x66 // DIG3字命令
- #define CH450_DIG4_ADDR 0x68 // DIG4字命令
- #define CH450_DIG5_ADDR 0x6A // DIG5字命令
- #define CH450_DIG6_ADDR 0x6C // DIG6字命令
- #define CH450_DIG7_ADDR 0x6E // DIG7字命令
-
- unsigned char CH450_Read(void);
- void CH450_Write(uint8_t cmd);
- void CH450_Init(void);
-
- #endif
-
main中创建线程之后延时1秒让CH450稳定复位
- int main(void)
- {
-
- ADC_thread = rt_thread_create("ADC",
- ADC_thread_entry,
- RT_NULL,
- sizeof(ADC_stack),
- 4,
- 10);
-
- if (ADC_thread != RT_NULL)
- rt_thread_startup(ADC_thread);
-
-
- rt_thread_mdelay(1000);
-
- CH450_Write(0x22);
- return 0;
- }
线程中定期读取按键编码,rt_kprintf貌似也不能输出十六进制,就先输出十进制先验证下功能吧!
- static void ADC_thread_entry(void *parameter)
- {
- while (1)
- {
- if(ADC_GetINTStatus(ADC1, ADC_INT_EC) != RESET){
- ADC_value = ADC_GetConversionValue(ADC1)*3.3f/4095;
- OLED_Showdecimal(10,10,ADC_value,2,3,16);、、OLED刷屏
- OLED_Refresh();
- ADC_SoftwareStartConvCtrl(ADC1, ENABLE);
- }
- rt_kprintf("KEY_Val:%d\r\n",CH450_Read());
- rt_thread_mdelay(300);
-
- }
- }
按下不同的按键可以看到打印值的改变,
|