STC32G12K128内部集成的I2C总线实现oled12864显示

STC32G 系列的单片机内部集成了一个 I2C 串行总线控制器。I2C 是一种高速同步通讯总线,通讯使用 SCL(时钟线)和 SDA(数据线)两线进行同步通讯。对于 SCL 和 SDA 的端口分,STC32G 系列的单片机提供了切换模式,可将 SCL 和 SDA 切换到不同的 I/O 口上,以方便用户将一组 I2C 总线当作多组进行分时复用。与标准 I2C 协议相比较,忽略了如下两种机制:

 发送起始信号(START)后不进行仲裁
 时钟信号(SCL)停留在低电平时不进行超时检测

STC32G 系列的 I2C 总线提供了两种操作模式:主机模式(SCL 为输出口,发送同步时钟信号)和从机模式(SCL 为输入口,接收同步时钟信号),这里要实现oled12864的显示,所以用到的是主机模式。

如上图所示,要用到的初始化函数为:void    I2C_Init(I2C_InitTypeDef *I2Cx),在主机模式下要对结构体的属性进行设置的只有:I2C_InitStructure.I2C_Mode,I2C_InitStructure.I2C_Enable, I2C_InitStructure.I2C_Speed,I2C_InitStructure.I2C_MS_WDTA,

从stc32g的数据手册知道内部集成的I2C总线功能是有规定引脚的,这里我们选择SCL:P25,SDA:P24:

 所以,我们的I2C初始化函数为:

void	I2C_config(void)
{
	I2C_InitTypeDef		I2C_InitStructure;
	I2C_InitStructure.I2C_Mode      = I2C_Mode_Master;		//主从选择   I2C_Mode_Master, I2C_Mode_Slave
	I2C_InitStructure.I2C_Enable    = ENABLE;							//I2C功能使能,   ENABLE, DISABLE
	I2C_InitStructure.I2C_Speed     = 13;							 		//I2C总线速度,   0~63
	I2C_InitStructure.I2C_MS_WDTA   = DISABLE;							//使能主机自动发送设置,   ENABLE, DISABLE
	I2C_Init(&I2C_InitStructure);
	
	I2C_SW(I2C_P24_P25);					//I2C_P14_P15,I2C_P24_P25,I2C_P76_P77,I2C_P33_P32
}

 接下来看一下官方的库函数中的STC32G_I2C.c文件

//========================================================================
// 函数: u8	Get_MSBusy_Status (void)
// 描述: 获取主机忙碌状态.
// 参数: none.
// 返回: 主机忙碌状态.
// 版本: V1.0, 2012-11-22
//========================================================================
u8 Get_MSBusy_Status(void)
{
	return (I2CMSST & 0x80);
}

//========================================================================
// 函数: void	Wait (void)
// 描述: 等待主机模式I2C控制器执行完成I2CMSCR.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2012-11-22
//========================================================================
void Wait()
{
	while (!(I2CMSST & 0x40));
	I2CMSST &= ~0x40;
}

//========================================================================
// 函数: void Start (void)
// 描述: I2C总线起始函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void Start()
{
	I2CMSCR = 0x01;                         //发送START命令
	Wait();
}

//========================================================================
// 函数: void SendData (char dat)
// 描述: I2C发送一个字节数据函数.
// 参数: 发送的数据.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendData(char dat)
{
	I2CTXD = dat;                           //写数据到数据缓冲区
	I2CMSCR = 0x02;                         //发送SEND命令
	Wait();
}

//========================================================================
// 函数: void RecvACK (void)
// 描述: I2C获取ACK函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void RecvACK()
{
	I2CMSCR = 0x03;                         //发送读ACK命令
	Wait();
}

//========================================================================
// 函数: char RecvData (void)
// 描述: I2C读取一个字节数据函数.
// 参数: none.
// 返回: 读取数据.
// 版本: V1.0, 2020-09-15
//========================================================================
char RecvData()
{
	I2CMSCR = 0x04;                         //发送RECV命令
	Wait();
	return I2CRXD;
}

//========================================================================
// 函数: void SendACK (void)
// 描述: I2C发送ACK函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendACK()
{
	I2CMSST = 0x00;                         //设置ACK信号
	I2CMSCR = 0x05;                         //发送ACK命令
	Wait();
}

//========================================================================
// 函数: void SendNAK (void)
// 描述: I2C发送NAK函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendNAK()
{
	I2CMSST = 0x01;                         //设置NAK信号
	I2CMSCR = 0x05;                         //发送ACK命令
	Wait();
}

//========================================================================
// 函数: void Stop (void)
// 描述: I2C总线停止函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void Stop()
{
	I2CMSCR = 0x06;                         //发送STOP命令
	Wait();
}

//========================================================================
// 函数: void SendCmdData (u8 cmd, u8 dat)
// 描述: I2C发送一个字节数据函数.
// 参数: 命令/数据.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void SendCmdData(u8 cmd, u8 dat)
{
	I2CTXD = dat;                           //写数据到数据缓冲区
	I2CMSCR = cmd;                          //设置命令
	Wait();
}

//========================================================================
// 函数: void	I2C_WriteNbyte(u8 addr, u8 *p, u8 number)
// 描述: I2C写入数据函数.
// 参数: addr: 指定地址, *p写入数据存储位置, number写入数据个数.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void I2C_WriteNbyte(u8 addr, u8 *p, u8 number)  /*  WordAddress,First Data Address,Byte lenth   */
{
	Start();                                //发送起始命令
	SendData(SLAW);                         //发送设备地址+写命令
	RecvACK();
	SendData(addr);                         //发送存储地址
	RecvACK();
	do
	{
		SendData(*p++);
		RecvACK();
	}
	while(--number);
	Stop();                                 //发送停止命令
}

//========================================================================
// 函数: void	I2C_ReadNbyte(u8 addr, u8 *p, u8 number)
// 描述: I2C读取数据函数.
// 参数: addr: 指定地址, *p读取数据存储位置, number读取数据个数.
// 返回: none.
// 版本: V1.0, 2020-09-15
//========================================================================
void I2C_ReadNbyte(u8 addr, u8 *p, u8 number)   /*  WordAddress,First Data Address,Byte lenth   */
{
	Start();                                //发送起始命令
	SendData(SLAW);                         //发送设备地址+写命令
	RecvACK();
	SendData(addr);                         //发送存储地址
	RecvACK();
	Start();                                //发送起始命令
	SendData(SLAR);                         //发送设备地址+读命令
	RecvACK();
	do
	{
		*p = RecvData();
		p++;
		if(number != 1) SendACK();          //send ACK
	}
	while(--number);
	SendNAK();                              //send no ACK	
	Stop();                                 //发送停止命令
}

 这个文件中有我们所熟知的I2C通信所必须的Wait(),Start(),Senddata()等的函数,它们的用法用过I2C通信的相信都知道了,但在STC32G_I2C.h这个头文件中只包含了以下几个函数的声明:

void	I2C_Init(I2C_InitTypeDef *I2Cx);
void	I2C_WriteNbyte(u8 addr, u8 *p, u8 number);
void	I2C_ReadNbyte( u8 addr, u8 *p, u8 number);
u8 Get_MSBusy_Status(void);
void SendCmdData(u8 dat, u8 cmd);

所以我们使用I2C总线有两种方法,第一种是把所有函数的声明都添加到头文件中,这样就可以调用Wait(),Start(),Senddata()等函数;第二种方法是用头文件中给的函数,也就是I2C_WriteNbyte(u8 addr, u8 *p, u8 number)这个函数。这里我们详细讲第二种方法,I2C_WriteNbyte()这个函数需要输入三个参数,u8 addr, u8 *p, u8 number,这里指定地址我们可以理解为对oled是进行写数据操纵还是写命令操作,所以输入时输入以下两个中一个就行:

#define OLED_CMD  0x00	//写命令
#define OLED_DATA 0x40	//写数据

p为要输入数据或命令的指针,可以一次输入多个数据,number为数据数。这里还有一点要注意的:SLAW的宏定义需要修改如下:

#define SLAW    0x78

然后就可以移植中景园的oled51例程,需要修改的只有OLED_WR_Byte()这一函数:

void OLED_WR_Byte(u8 dat,u8 mode)
{
	#if 0
	Start();
	SendData(0x78);
	RecvACK();
	SendData(mode);
	RecvACK();
	SendData(dat);
	SendNAK();
	Stop();
	
	#else
	I2C_WriteNbyte(mode,&dat,1);
	
	#endif
	
}

然后就可以显示啦

 还有两点要注意的是,这里的memory mode 需要修改一下:

原因可能是库函数中定义的常量太多导致无法显示,修改后就可正常显示。而另一个问题是我发现在单独显示字符串,也就是在主函数中只调用OLED_ShowString()这一函数时oled无法显示,并且好像连单片机都无法正常使用,有大神路过的话希望能帮忙解惑一下。 

同样的,项目我放在主页资源上。

  • 21
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值