大家好,我是单片机爱好者-MCU起航。这一节我们介绍如何使用库函数方式控制STM8S103F3P6片上的IIC接口,也有的叫I2C。首先,我们看一下原理图,找到IIC接口的位置:
如图所示,在STM8S103F3P6的PB4和PB5管脚上,这是单片机自带的硬件IIC。学过51单片机的朋友,都接触过IIC。通过用普通的IO模拟IIC的时序,和24C02这样的芯片通信。
那么这里咱们使用什么代码演示呢?
演示的话,依然使用软件模拟IIC时序,管脚还是PB4和PB5。为什么不用硬件?因为我个人曾经做过一些简单的测试,硬件IIC使用的时候相对不是很稳定。当然,这不是说人家有问题,而是使用时的注意事项比较多,对于新手来说,建议从IO模拟开始。掌握熟练以后,可以根据需要换成硬件。
同时,这里同时提供了软件和硬件的代码供大家下载。根据文章结尾的提示就可以找到下载的位置。
好,这里咱们看一个例子,使用普通IO模拟IIC接口,和AT24C02通信,并且把主要信息打印到串口上。代码如下:
/* Includes ------------------------------------------------------------------*/
#include "stm8s.h"
#include "stm8_uart.h"
//#include <stdio.h>
#include "IIC_CONFIG.h"
/* Private defines -----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
void Delay(uint16_t nCount)
{
/* Decrement nCount value */
while (nCount != 0)
{
nCount--;
}
}
void main(void)
{
unsigned char a = 0;
unsigned int b = 0;
CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV2);
I2CC_Init();
Init_UART1();
write_24c02(0x10,0x25);
for(b = 0; b < 10000; b++); //必须要有一个延时
a = read_24c02(0x10);
UART1_SendData8(a);
while(1);
}
可以看到,主函数里进行了几个操作:
1、系统时钟设置为8MHZ。
2、相关GPIO初始化,软件模拟IIC时序。
3、串口初始化,后面讲串口。
4、在24C02的0x10位置写入数据0x25.
5、延时一段时间,读和写之间必须要隔一段时间,否则会出错。
6、读24C02的0x10位置的数据,并通过串口打印出来。
IIC接口的初始化,读操作、写操作,我都放在了一个C文件里,咱们直接看一下就醒了,有IIC操作经验的人,看一眼就懂了。
#include "IIC_CONFIG.h"
#define SCL_L GPIO_WriteLow(GPIOB, GPIO_PIN_4)
#define SCL_H GPIO_WriteHigh(GPIOB, GPIO_PIN_4)
#define SDA_L GPIO_WriteLow(GPIOB, GPIO_PIN_5)
#define SDA_H GPIO_WriteHigh(GPIOB, GPIO_PIN_5)
#define SDAM GPIO_ReadInputPin(GPIOB, GPIO_PIN_5)
#define SET_SCL_OUT() {GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_OUT_PP_HIGH_SLOW);}
#define SET_SDA_OUT() {GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_OUT_PP_HIGH_SLOW);}
#define SET_SDA_IN() {GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_IN_FL_NO_IT);}
//--------------------------------------------------------------
// Prototype : void I2C_Start(void)
// Calls : Delay_5us()
// Description : Start Singnal
//--------------------------------------------------------------
void I2CC_Init(void)
{
//I2C_CR1 &= 0xFE; // PE=0, disable I2C module
SET_SCL_OUT();
SET_SDA_OUT();
}
//--------------------------------------------------------------
// Prototype : void Delay_5us(void)
// Description : 大约延时5us
//--------------------------------------------------------------
void Delay_5us(void)
{
unsigned char i; //fcpu 8MHz 时
for (i=20; i>0; i--);
}
//--------------------------------------------------------------
// Prototype : void I2C_Start(void)
// Calls : Delay_5us()
// Description : Start Singnal
//--------------------------------------------------------------
void I2C_Start(void)
{
// SDA 1->0 while SCL High
SDA_H;
SCL_H;
Delay_5us();
SDA_L;
Delay_5us();
SCL_L;
}
//--------------------------------------------------------------
// Prototype : void I2C_Stop(void)
// Calls : Delay_5us()
// Description : Stop Singnal
//--------------------------------------------------------------
void I2C_Stop(void)
{
// SDA 0->1 while SCL High
SDA_L;
SCL_H;
Delay_5us();
SDA_H;
Delay_5us();
}
//--------------------------------------------------------------
// Prototype : void I2C_SendACK(uchar ack);
// Calls : Delay_5us()
// Parameters : bit ack:1-noack, 0-ack
// Description : Master device send ACK to slave device.
//--------------------------------------------------------------
void I2C_SendACK(uchar ack)
{
if(ack == 0)
{
SDA_L;
}
else
{
SDA_H;
}
SCL_H;
Delay_5us();
SCL_L;
Delay_5us();
}
//--------------------------------------------------------------
// Prototype : uchar I2C_SendByte(uchar sendDAT)
// Calls : Delay_5us()
// Parameters : uchar sendDAT---data to be send
// Return Value : CY--slave ack (1---noack,0---ack)
// Description : Send one byte to I2C
//--------------------------------------------------------------
uchar I2C_SendByte(uchar sendDAT)
{
uchar i,revack;
for (i= 0 ; i< 8; i++)
{
SCL_L;
Delay_5us();
if (sendDAT & 0x80) // write data
{
SDA_H;
}
else
{
SDA_L;
}
sendDAT <<= 1;
SCL_H;
Delay_5us();
}
SCL_L;
Delay_5us();
SET_SDA_IN();
SCL_H;
asm("nop");
asm("nop");
revack = (uchar)SDAM;
Delay_5us();
SCL_L;
SET_SDA_OUT();
Delay_5us();
return revack;
}
//--------------------------------------------------------------
// Prototype : uchar I2C_RecvByte()
// Calls : Delay_5us()
// Parameters : none
// Return Value : revDAT- received data
// Description : Receive one byte from I2C
//--------------------------------------------------------------
uchar I2C_RecvByte()
{
uchar i;
uchar revDAT = 0;
SDA_H; // latch the Data port befor reading
SET_SDA_IN();
for (i=0; i<8; i++)
{
revDAT <<= 1;
SCL_H;
asm("nop");
asm("nop");
if (SDAM)
{
revDAT |= 0x01;
}
else
{
revDAT &= 0xfe;
}
Delay_5us();
SCL_L;
Delay_5us();
}
SET_SDA_OUT();
return revDAT;
}
//--------------------------------------------------------------
// Prototype : void Write_PT2314(uchar wdata)
// Calls : I2C_Start(), I2C_Stop(),I2C_SendByte()
// Parameters : RegAddr-- target memory address,
// wrdata--- data to be writing
// Description : Write one byte to target memory
//--------------------------------------------------------------
void write_24c02(uchar regadd,uchar wdata)
{
I2C_Start();
I2C_SendByte(SlaveAddress); // Device Addr + Write (operation)
I2C_SendByte(regadd);
I2C_SendByte(wdata);
I2C_Stop();
}
u8 read_24c02(uchar regadd)
{
u8 revdata;
I2C_Start();
I2C_SendByte(SlaveAddress); // Device Addr + Write (operation)
I2C_SendByte(regadd);
I2C_Start();
I2C_SendByte(SlaveAddress+1); // Device Addr + Write (operation)
revdata = I2C_RecvByte();
I2C_Stop();
return revdata;
}
最后,编译、下载、上电,上电之前记得把串口连到电脑上,波特率9600.就能看到串口打印的字符“a”,功能正常!
打完收工!
对了,虽然这里使用软件模拟的方式写的代码,但我们也写了硬件IIC的代码,想要获取该程序完整的工程文件,可以关注公众号:单片机爱好者,然后回复关键词:STM8S。可以获取完整的下载链接,里面包含工程文件、视频、PPT、数据手册等所有相关资料。