|
- /*
- STC15单片机驱动iic注意事项
- 最近一个月在开发项目,用到的MCU是stc15,发现驱动iic的时候需要将io口设置成开漏输出才能稳定读取iic数据,如果设置成弱上拉就会掉数据。
- 于是我查了查开漏输出是怎么一回事,因为以前用AVR芯片的时候都是设置成弱上拉模式,但是STC15的单片机有点不一样。
- 在写字节函数里面需要加这么一句
-
- while(scl==0);
- 原因是主机发时钟给从机的时候,需要判断从机是否接受到这个信号,所以就要等
- */
- #include <reg52.h>
- #include <intrins.h>
- sbit SCL = P3^0;
- sbit SDA = P3^1;
- bit ack;
- // P0 P1 P2 P3 P4 P5 P6 P7 PCF8574
- // RS RW E <> D4 D5 D6 D7
- // 6 5 4 7 0 1 2 3
-
- //sbit RS=P2^0;
- //sbit Rw=P2^1;
- //sbit E =P2^2;
- sbit button1 =P1^0;
- unsigned char LCD_data;
- unsigned char code digit[ ]={"0123456789"}; //定义字符数组显示数字
- /*
- bt0=date&0x01;
- bt1=date&0x02;
- bt2=date&0x04;
- bt3=date&0x08;
- bt4=date&0x10;
- bt5=date&0x20;
- bt6=date&0x40;
- bt7=date&0x80;
- */
- //*****************延时************************
- void delay_nus(unsigned int n) //N us延时函数
- {
- unsigned int i=0;
- for (i=0;i<n;i++)
- _nop_();
- }
- void delay_nms(unsigned int n) //N ms延时函数
- {
- unsigned int i,j;
- for (i=0;i<n;i++)
- for (j=0;j<1140;j++);
- }
- void nop4()
- {
- _nop_(); //等待一个机器周期
- _nop_(); //等待一个机器周期
- _nop_(); //等待一个机器周期
- _nop_(); //等待一个机器周期
- }
- //***************************************88
- void Start()
- {
- SDA=1;
- _nop_();
- SCL=1;
- nop4();
- SDA=0;
- nop4();
- SCL=0;
- _nop_();
- _nop_();
- }
- void Stop()
- {
- SDA=0;
- _nop_();
- SCL=0;
- nop4();//>4us后SCL跳变
- SCL=1;
- nop4();
- SDA=1;
- _nop_();
- _nop_();
- }
- //******************************************
- void Write_A_Byte(unsigned char c)
- {
- unsigned char BitCnt;
- for(BitCnt=0;BitCnt<8;BitCnt++) //要传送的数据长度为8位
- {
- if((c<<BitCnt)&0x80) SDA=1; //判断发送位
- else SDA=0;
- _nop_();
- SCL=1; //置时钟线为高,通知被控器开始接收数据位
- nop4();
- _nop_();
- SCL=0;
- }
- _nop_();
- _nop_();
- SDA=1; //8位发送完后释放数据线,准备接收应答位
- _nop_();
- _nop_();
- SCL=1;
- _nop_();
- _nop_();
- _nop_();
- if(SDA==1)ack=0;
- else ack=1; //判断是否接收到应答信号
- SCL=0;
- _nop_();
- _nop_();
- }
- bit Write_Random_Address_Byte(unsigned char add,unsigned char dat)
- {
- Start(); //启动总线
- Write_A_Byte(add); //发送器件地址
- if(ack==0)return(0);
- Write_A_Byte(dat); //发送数据
- if(ack==0)return(0);
- Stop(); //结束总线
- return(1);
- }
- //********************液晶屏使能*********************
- void Enable_LCD_write()
- {
- LCD_data|=(1<<(3-1));//E=1;
- Write_Random_Address_Byte(0x40,LCD_data);
- delay_nus(2);
- LCD_data&=~(1<<(3-1));//E=0;
- Write_Random_Address_Byte(0x40,LCD_data);
- }
- //*************写命令****************************
- void LCD_write_command(unsigned char command)
- {
- delay_nus(16);
- LCD_data&=~(1<<(1-1));//RS=0;
- LCD_data&=~(1<<(2-1));//RW=0;
- Write_Random_Address_Byte(0x40,LCD_data); // PCF8574 40H, PCF8574A 70H
- // 0x27, 0x20, 0x3F
- LCD_data&=0x0f; //清高四位
- LCD_data|=command & 0xf0; //写高四位
- Write_Random_Address_Byte(0x40,LCD_data);
- Enable_LCD_write();
- command=command<<4; //低四位移到高四位
- LCD_data&=0x0f; //清高四位
- LCD_data|=command&0xf0; //写低四位
- Write_Random_Address_Byte(0x40,LCD_data);
- Enable_LCD_write();
- }
- //*************写数据****************************
- void LCD_write_data(unsigned char value)
- {
- delay_nus(16);
- LCD_data|=(1<<(1-1));//RS=1;
- LCD_data&=~(1<<(2-1));//RW=0;
- Write_Random_Address_Byte(0x40,LCD_data);
- LCD_data&=0X0f; //清高四位
- LCD_data|=value&0xf0; //写高四位
- Write_Random_Address_Byte(0x40,LCD_data);
- Enable_LCD_write();
- value=value<<4; //低四位移到高四位
- LCD_data&=0x0f; //清高四位
- LCD_data|=value&0xf0; //写低四位
- Write_Random_Address_Byte(0x40,LCD_data);
- Enable_LCD_write();
- }
- //**********************设置显示位置*********************************
- void set_position(unsigned char x,unsigned char y)
- {
- unsigned char position;
- if (y == 0)
- position = 0x80 + x;
- else
- position = 0xc0 + x;
- LCD_write_command(position);
- }
- //**********************显示字符串*****************************
- void display_string(unsigned char x,unsigned char y,unsigned char *s)
- {
- set_position(x,y);
- while (*s)
- {
- LCD_write_data(*s);
- s++;
- }
- }
- //********************显示数字*******************************xs
- void display_num(unsigned char x,unsigned char y,unsigned int num)
- {
- unsigned char i,j,k,m,n;
- set_position(x,y);
- i=num/10000;
- j=num/1000%10;
- k=num/100%10;
- m=num/10%10;
- n=num%10;
- LCD_write_data(digit[i]); //将万位数字的字符常量写入LCD
- LCD_write_data(digit[j]); //将千位数字的字符常量写入LCD
- LCD_write_data(digit[k]);
- LCD_write_data(digit[m]);
- LCD_write_data('.');
- LCD_write_data(digit[n]);
- }
- //*************液晶初始化****************************
- void LCD_init(void)
- {
- LCD_write_command(0x28);
- delay_nus(40);
- LCD_write_command(0x28);
- delay_nus(40);
- Enable_LCD_write();
- delay_nus(40);
- LCD_write_command(0x28); //4位显示!!!!!!!!!!!!!!!!!!
- LCD_write_command(0x0c); //显示开
- LCD_write_command(0x01); //清屏
- delay_nms(2);
- }
- //
- //********************按键*********************
- void button()
- {
- if(button1==0)
- {
- LCD_data|=(1<<(4-1));//E=1;
- Write_Random_Address_Byte(0x40,LCD_data);
- }
- if(button1==1)
- {
- LCD_data&=~(1<<(4-1));//E=0;
- Write_Random_Address_Byte(0x40,LCD_data);
- }
- }
- void main(void)
- {
- int i;
- LCD_init();
- display_string(0,0,"Hello Today!"); //显示一段文字
- while(1)
- {
- button();
- display_num(0,1,i);
- delay_nms(50);
- i++;
- }
- }
复制代码- //The basic concept of bit-bang i2c is same either you implement it in C or Assembly language.
- #define SDA P0_0
- #define SCL P0_1
- void I2CInit()
- {
- SDA = 1;
- SCL = 1;
- }
- void I2CStart()
- {
- SDA = 0;
- SCL = 0;
- }
- void I2CRestart()
- {
- SDA = 1;
- SCL = 1;
- SDA = 0;
- SCL = 0;
- }
- void I2CStop()
- {
- SCL = 0;
- SDA = 0;
- SCL = 1;
- SDA = 1;
- }
- void I2CAck()
- {
- SDA = 0;
- SCL = 1;
- SCL = 0;
- SDA = 1;
- }
- void I2CNak()
- {
- SDA = 1;
- SCL = 1;
- SCL = 0;
- SDA = 1;
- }
- unsigned char I2CSend(unsigned char Data)
- {
- unsigned char i, ack_bit;
- for (i = 0; i < 8; i++) {
- if ((Data & 0x80) == 0)
- SDA = 0;
- else
- SDA = 1;
- SCL = 1;
- SCL = 0;
- Data<<=1;
- }
- SDA = 1;
- SCL = 1;
- ack_bit = SDA;
- SCL = 0;
- return ack_bit;
- }
- unsigned char I2CRead()
- {
- unsigned char i, Data=0;
- for (i = 0; i < 8; i++) {
- SCL = 1;
- if(SDA)
- Data |=1;
- if(i<7)
- Data<<=1;
- SCL = 0;
- }
- return Data;
- }
- /*****************************************
- * Write to slave device with
- * slave address e.g. say 0x20
- *****************************************/
- /* Init i2c ports first */
- I2CInit();
- /* Send start condition */
- I2CStart();
- /* Send slave address */
- ack = I2CSend(0x20);
- /*
- * ack == 1 => NAK
- * ack == 0 => ACK
- */
- ack = I2CSend(0x07);
- /* Send another data */
- ack = I2CSend(0x10);
- /* Send stop condition */
- I2CStop();
- /*****************************************
- * Read from slave device with
- * slave address e.g. say 0x20
- *****************************************/
- /* Init i2c ports first - Should be done once in main */
- I2CInit();
- /* Send start condition */
- I2CStart();
- /*
- * Send slave address with Read bit set
- * So address is 0x20 | 1 = 0x21
- */
- I2CSend(0x21);
- data = I2CRead();
- /* Send ack */
- I2CAck();
- /* Read last byte */
- data = I2CRead();
- /*
- * Send nak for last byte to indicate
- * End of transmission
- */
- I2CNak();
- /* Send stop condition */
- I2CStop();
- /*****************************************************************/
- //I am considering same scenario as in assembly sample, DS1307 connected to 8051 microcontroller. Here is a sample code for reading DS1307 registers in C
- I2CStart(); /* start condition */
- I2CSend(0xD0); /* Slave address + Write */
- I2CSend(0x00); /* Starting address of RTC */
- I2CRestart(); /* Repeated start condition */
- I2CSend(0xD1); /* Slave address + Read */
- /* Read 8 registers from RTC */
- for (i = 0; i < 8; i++) {
- /* Read and store in array */
- /* This is much simpler than in Assembly :) */
- a[i] = I2CRead();
-
- /* check for last byte */
- if(i == 7)
- I2CNak(); /* NAK if last byte */
- else
- I2CAck(); /* ACK for all read bytes */
- }
- /* Reading finished send stop condition */
- I2CStop();
- //Following code example uses the C code provided in I2C Implementation on PIC written for PIC16F877A microcontroller MSSP module.
- void main()
- {
- /* Buffer where we will read/write our data */
- unsigned char I2CData[] = {0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09, 0x00};
- unsigned char i;
- /* Initialize I2C Port */
- I2CInit();
- /* Send Start condition */
- I2CStart();
- /* Send DS1307 slave address with write operation */
- I2CSend(0xD0);
- /* Send subaddress 0x00, we are writing to this location */
- I2CSend(0x00);
-
- /* Loop to write 8 bytes */
- for (i = 0; i < 8; i++) {
- /* send I2C data one by one */
- I2CSend(I2CInitval[i]);
- }
-
- /* Send a stop condition - as transfer finishes */
- I2CStop();
-
- /* We will now read data from DS1307 */
- /* Reading for a memory based device always starts with a dummy write */
- /* Send a start condition */
- I2CStart();
- /* Send slave address with write */
- I2CSend(0xD0);
- /* Send address for dummy write operation */
- /* this address is actually where we are going to read from */
- I2CSend(0x00);
-
- /* Send a repeated start, after a dummy write to start reading */
- I2CRestart();
- /* send slave address with read bit set */
- I2CSend(0xD1);
- /* Loop to read 8 bytes from I2C slave */
- for (i = 8; i > 0; i--) {
- /* read a byte */
- I2CData[i] = I2CRead();
- /* ACK if its not the last byte to read */
- /* if its the last byte then send a NAK */
- if (i - 1)
- I2CAck();
- else
- I2CNak();
- }
- /* Send stop */
- I2CStop();
- /* end of program */
- while(1);
- }
复制代码
|
|