GD32E230C8T6《调试篇》之 (软件) IIC通信 + GN1650驱动芯片 + 4位8段数码管显示(成功)
- IIC是什么
- IIC简介
- 按键扫描
- 代码
-
- [1)DIG2短按只++一次,长按超过1s 一直 ++;DIG3短按只 - - 一次,长按超过1s 一直 - -](#1)DIG2短按只++一次,长按超过1s 一直 ++;DIG3短按只 - - 一次,长按超过1s 一直 - -)
IIC是什么
IIC也称I2C,是一个多主从的串行总线,由飞利浦公司发明的通讯总线,属于半双工同步传输类总线,仅由两条线就能完成多机通讯,一条SCL时钟线,另外一条双向数据线SDA,IIC总线要求每个设备SCL/SDA线都是漏极开路模式,因此必须带上拉电阻才能正常工作。I2C协议占用引脚少,硬件实现简单,可扩展性强,I2C数据传输速率有标准模式(100kbps)、快速模式(400kbps)和高速模式(3.4Mbps)。
IIC简介
IIC总线的SDA和SCL两根总线需要上拉,使总线处于空闲状态。IIC总线一共有两种状态、四种信号。除此之外还需要了解IIC总线的数据有效性。
1)IIC总线物理连接
SDA 和SCL 都是双向线路,都通过一个电流源或上拉电阻连接到正的电源电压。当总线空闲时,这两条线路都是高电平。连接到总线的器件输出级必须是漏极开路或集电极开路才能执行线与的功能。
总线器件数目:由于每一个IIC器件在IIC总线上都有一个确切的7位地址码,这也意味着一条IIC总线上最多可链接127(0X00位地址不使用)个地址互不相同的IIC器件。但在单条IIC总线上链接不多与127个器件的同时,必须要满足总线电容不能超过400pF(协议规定),总线之所以规定电容大小是因为,IIC的OD要求外部有电阻上拉,电阻和总线电容产生了一个RC延时效应,电容越大信号的边沿就越缓,有可能带来信号质量风险。传输速度越快,信号的窗口就越小,上升沿下降沿时间要求更短更陡峭,所以RC乘积必须更小。实际设计中经验值大概是8个器件左右。
2)IIC时序协议
时序图:
IIC总线进行数据传送时,在SCL的每个时钟脉冲期间传输一个数据位,时钟信号SCL为高电平期间,数据线SDA上的数据必须保持稳定,只有在时钟线SCL上的信号为低电平期间,数据线SDA上的高电平或低电平状态才允许变化,因为当SCL是高电平时,数据线SDA的变化被规定为控制命令(START或STOP,也就是起始信号和停止信号)。
IDLE表示总线空闲状态。此状态下时钟信号SCL和数据信号SDL均为高电 平,此时无I2C设备工作。时钟线(SCL)和数据线(SDA)接上拉电阻,默认高电平,就是为了表示总线是空闲状态。
表示起始状态。在空闲状态下,时钟信号SCL继续保持高电平,数据信号SDL出现由高电平转换为低电平的下降沿,此时产生一个起始信号,与总线相连的I2C设备检测到起始信号之后,进入起始状态等待控制字节的输入。
I2C通信的停止信号由主设备发出,SCL保持高电平,SDA由低电平跳变到高电平。
应答信号接收端收到有效数据后需要向对方响应的信号,发送端每发送一个字节(8位)数据,在第9个时钟周期释放数据线去接收对方的应答。
在第9个时钟周期:
当SDA是低电平为有效应答(ACK),表示对方接收成功;
当SDA是高电平为无效应答(NACK),表示对方没有接收成功。
注意:数据发射端需要在第9个时钟周期等待接收端的应答信号
IIC协议的读写操作都是一字节大小,从高到低收发数据
版权声明:本文为CSDN博主「烟雨江南、」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guyuani/article/details/127709375
以上内容为转载!!! 下面是自己写的
按键扫描
GN1650 芯片有按键消抖,所以不需要软件消抖;
代码
1)DIG2短按只++一次,长按超过1s 一直 ++;DIG3短按只 - - 一次,长按超过1s 一直 - -
c
const uint8_t LEDENCODE[] = {0x03F,0x006,0x05B,0x04F,0x066,0x06D,0x07D,0x007,0x07F,0x06F};
//const LEDNUM[][3] = {{0x38,0x3F,0x3E,0x79},{},{}};
#define READ_SDA gpio_input_bit_get(GPIOB,GPIO_PIN_7)
#define LEDDOT 0x80
#define MAXNUM 10
#define TIMEPRESS 350 //key press times
#define DIG1 17
#define DIG2 25
#define DIG3 21
#define DIG4 29
#define ADDRMAX 512
uint8_t i;
uint16_t value=0;
void myGPIO_init(void)
{
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOA);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_2MHZ,GPIO_PIN_0);//PB6_42 I2C0_SCL GPIO_OTYPE_PP推挽输出
gpio_mode_set(GPIOA, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_0);
}
/****** 按键处理函数
*一定不能有do while , delay 等阻塞语句,要快进快出,main函数有更重要的事情要做
******/
void keycheck(void)
{
uint16_t KeyNum;
uint16_t LastKeyNum = 0;
static uint8_t Keyleased=1,fastCnt=0;
static uint16_t keydowntime = 0;
//uint8_t lontimeflag = 1;
KeyNum = GetKey();
switch(KeyNum)
{
case DIG2:
if(keydowntime++ >= TIMEPRESS )//long press ++
{
keydowntime=TIMEPRESS;
if(++fastCnt>=10)//add press times 分频
{
fastCnt=0;
value++;
if(value > ADDRMAX) value = 1; //512 to 1
}
}
else if(Keyleased && keydowntime < TIMEPRESS )//short press ++
{
value++;
Keyleased = 0;//keydown locked 加锁
if(value > ADDRMAX) value = 1; //512 to 1
}
break;
case DIG3:
if( keydowntime++ >= TIMEPRESS)//long press --
{
keydowntime=TIMEPRESS;
if(++fastCnt>=10)//add press times 分频
{
fastCnt=0;
value--;
if(value == 0) value = ADDRMAX; //0 to 512
}
}
else if(Keyleased && keydowntime++ < TIMEPRESS )//short press --
{
value--;
Keyleased=0; //keydown locked 加锁
if(value == 0) value = ADDRMAX; //0 to 512
}
break;
default:
Keyleased=1;//keydown loosed
fastCnt=0;
keydowntime = 0;
break;
}
}
//主函数处理
int main(void)
{
uint8_t flag = 0;
systick_config();
myGPIO_init();
delay_ms(10);
i2c_init();
while(1)
{
flag =!flag;
gpio_bit_write(GPIOA,GPIO_PIN_0,flag);
delay_ms(1);
keycheck();
GN1650_display();
//do work1
//do work2
}
}
/********** 数码管显示 **********/
void GN1650_display(void)
{
GN1650_Wrt_RAM(0x68,LEDENCODE[value/1000%10]);//high //0x48 系统指令 0x41//4级亮度 8段显示 显示开
GN1650_Wrt_RAM(0x6A,LEDENCODE[value/100%10] );// | LEDDOT);
GN1650_Wrt_RAM(0x6C,LEDENCODE[value/10%10]);
GN1650_Wrt_RAM(0x6E,LEDENCODE[value%10]); //low
GN1650_Wrt_RAM(0x48,0x01);
// GN1650_Wrt_RAM(0x68,LEDENCODE[value/1000%10]);//high //0x48 系统指令 0x41//4级亮度 8段显示 显示开
// GN1650_Wrt_RAM(0x6A,LEDENCODE[value/100%10] | LEDDOT);
// GN1650_Wrt_RAM(0x6C,LEDENCODE[value/10%10]);
// GN1650_Wrt_RAM(0x6E,LEDENCODE[value%10]); //low
}
/********** 数码管无显示 **********/
void GN1650_display_D(void)
{
GN1650_Wrt_RAM(0x48,0x00);
}
/********** IIC初始化 *********/
void i2c_init(void)
{
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
/* enable I2C0 clock */
rcu_periph_clock_enable(RCU_I2C0);
/* connect PB6 to I2C0_SCL */
gpio_af_set(GPIOB,GPIO_AF_1,GPIO_PIN_6);
/* connect PB7 to I2C0_SDA */
gpio_af_set(GPIOB,GPIO_AF_1,GPIO_PIN_7);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ,GPIO_PIN_6);//PB6_42 I2C0_SCL
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_6);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ,GPIO_PIN_7);//PB7_43 I2C0_SDA
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_7);
/* configure I2C0 clock */
//i2c_clock_config(I2C0,60000,I2C_DTCY_2);
/* enable I2C0 */
i2c_enable(I2C0);
/* enable acknowledge */
i2c_ack_config(I2C0,I2C_I2CMODE_ENABLE);
/* 空闲状态 */
gpio_bit_write(GPIOB,GPIO_PIN_6,1);
gpio_bit_write(GPIOB,GPIO_PIN_7,1);
GN1650_Wrt_RAM(0x48,0x00);//关闭显示
}
void SDA_Rx(void) //主机recv from 从机
{
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
gpio_mode_set(GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO_PIN_7);
}
void SDA_Tx(void)
{
/* enable GPIOB clock */
rcu_periph_clock_enable(RCU_GPIOB);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ,GPIO_PIN_7);//PB7_43 I2C0_SDA
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_PULLUP, GPIO_PIN_7);
}
void IIC_SCL(uint8_t n)
{
gpio_bit_write(GPIOB,GPIO_PIN_6,n);
}
void IIC_SDA(uint8_t n)
{
gpio_bit_write(GPIOB,GPIO_PIN_7,n);
}
static void IIC_Delay(void)
{
__IO uint16_t cnt=1;
while(cnt--);
}
/*********************模拟IIC通信****************/
/*
*函数功能:IIC起始
*提 示:
*输入参数:无
*输出参数:无
*返回值 :无
*/
static void IIC_Start1(void)
{
SDA_Tx();
//2、SCL 1
IIC_SCL(1);
//3、SDA 1
IIC_SDA(1);
//延时5us
IIC_Delay();
//4、SCL 0
IIC_SDA(0);
//延时5us
IIC_Delay();
//5、SDA 0
IIC_SCL(0);
//延时5us
IIC_Delay();
}
/*
*函数功能:IIC结束
*提 示:
*输入参数:无
*输出参数:无
*返回值 :无
*/
static void IIC_Stop1(void)
{
//2、SCL 1
IIC_SCL(1);
//3、SDA 0
IIC_SDA(0);
//延时5us
IIC_Delay();
//4、SDA 1
IIC_SDA(1);
//延时5us
IIC_Delay();
}
/*
*函数功能:IIC应答
*提 示:
*输入参数:无
*输出参数:无
*返回值 :无
*/
void IIC_ACK(void)
{
SDA_Rx();
IIC_SCL(0);
IIC_Delay();
IIC_SDA(0);
IIC_Delay();
IIC_SCL(1);
IIC_Delay();
IIC_SCL(0);
IIC_Delay();
SDA_Tx();
IIC_SDA(0);
IIC_Delay();
}
/****************模拟IIC通信**************/
/* 描述:一个字节数据发送函数
* 参数: 无
* 返回值:无 */
void IIC_Wrt_Byte(uint8_t data)
{
int i;
IIC_SCL(0); //拉低时钟开始数据传输
for(i = 0;i < 8;i++)
{
IIC_SDA((data & 0x80)>0 ); //check bit7
data <<= 1;
IIC_Delay(); //这三个延时都是必须的
IIC_SCL(1);
IIC_Delay();
IIC_SCL(0);
IIC_Delay();
}
}
/* 描述:一个字节数据接收函数
* 参数: 无
* 返回值:接收到的字节数据 */
uint8_t IIC_Rev_Byte(void)
{
uint8_t dat=0;
uint8_t i;
SDA_Rx(); /* 设置数据线为输入方式 */
IIC_Delay();
for(i = 0;i < 8;i++)
{
IIC_SCL(0); /* 设置时钟线为低,准备接收数据位 */
IIC_Delay();
IIC_SCL(1); /* 设置时钟线为高使数据线上数据有效 */
if(READ_SDA) dat|=0x80; //同ret++; /* 读数据位,接收的数据位放入ret中 */
dat>>=1;
IIC_Delay();
}
IIC_SCL(0);
return dat;
}
// write to RAM
void GN1650_Wrt_RAM(uint8_t Address, uint8_t Data)
{
IIC_Start1();
IIC_Wrt_Byte(Address);
IIC_ACK();
IIC_Wrt_Byte(Data);
IIC_ACK();
IIC_Stop1();
}
/********** 按键扫描函数 get 按键 ID **********/
uint8_t GetKey(void)
{
uint8_t key=0;
IIC_Start1();
IIC_Wrt_Byte(0x49);
IIC_ACK();
key= IIC_Rev_Byte();
IIC_ACK();
IIC_Stop1();
return key;
}