iic设备驱动程序.doc
- 格式:doc
- 大小:424.60 KB
- 文档页数:33
I2C总线简介1.概述:I²C是Inter-Integrated Circuit的缩写,发音为"eye-squared cee" or"eye-two-cee", 它是一种两线接口。
I²C 只是用两条双向的线,一条 Serial Data Line (SDA) ,另一条Serial Clock (SCL)。
SCL:上升沿将数据输入到每个EEPROM器件中;下降沿驱动EEPROM器件输出数据。
(边沿触发)SDA:双向数据线,为OD门,与其它任意数量的OD与OC门成"线与"关系。
2.输出级每一个I2C总线器件内部的SDA、SCL引脚电路结构都是一样的,引脚的输出驱动与输入缓冲连在一起。
其中输出为漏极开路的场效应管,输入缓冲为一只高输入阻抗的同相器,这种电路具有两个特点:1)由于SDA、SCL为漏极开路结构(OD),因此它们必须接有上拉电阻,阻值的大小常为1k8, 4k7 and 10k ,但1k8 时性能最好;当总线空闲时,两根线均为高电平。
连到总线上的任一器件输出的低电平,都将使总线的信号变低,即各器件的SDA及SCL都是线"与"关系。
2)引脚在输出信号的同时还将引脚上的电平进行检测,检测是否与刚才输出一致,为"时钟同步"和"总线仲裁"提供了硬件基础。
3.主设备与从设备系统中的所有外围器件都具有一个7位的"从器件专用地址码",其中高4位为器件类型,由生产厂家制定,低3位为器件引脚定义地址,由使用者定义。
主控器件通过地址码建立多机通信的机制,因此I2C总线省去了外围器件的片选线,这样无论总线上挂接多少个器件,其系统仍然为简约的二线结构。
终端挂载在总线上,有主端和从端之分,主端必须是带有CPU的逻辑模块,在同一总线上同一时刻使能有一个主端,可以有多个从端,从端的数量受地址空间和总线的最大电容 400pF的限制。
RDA5807m驱动程序+ IIC 程序/****************************************************************************** ************ 介绍: RD5807M收音机程序供电3.3v 主控使用51单片机显示使用LCD1602** 作者: 胖子** 时间:2016-1-5** 地点:桂林电子科技大学******************************************************************************* **********/#include <reg51.h>#include <string.h>#include <intrins.h>#define uchar unsigned char#define uint unsigned int#define ulint unsigned long int#define lint long intuchar code xian[4][4]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};uchar code hang[]={0xfe,0xfd,0xfb,0xf7}; //矩阵键盘扫描使用//RDA 的寄存器地址#define RDA_R00 0X00 //读出16个位的ID =0X5800#define RDA_R02 0X02 //DHIZ[15],DMUTE[14]静音,MONO[13]声道,BASS[12]重低音,SEEKUP[9],SEEK[8],SKMODE[7],CLK_MODE[6:4]时钟源选择,SOFTRESET[1]软复位,ENABLE[0]电源使能#define RDA_R03 0X03 //CHAN[15:6],TUNE[4],BAND[3:2],SPACE[1:0] 设置频率带宽步长#define RDA_R04 0X04 //STCIEN[14],DE[11],I2Senable[6],#define RDA_R05 0X05 //INT_MODE[15],SEEKTH[14:8](设定自动搜索信号强度阀值),LNA_PORT_SEL[7:6]=0b10,LNA_ICSEL_BIT[5:4],VOLUME[3:0]音量;#define RDA_R0A 0X0A //STC[14]seek complete SF[13]seek fail readchan[9:0]当前频道#define RDA_R0B 0X0B //RSSI[15:9],FM TRUE[8]当前频道是一个节目台#define RDA_READ 0X23 //读RDA5807#define RDA_WRITE 0X22 //写RDA5807//IO操作函数sbit SDA=P2^1;sbit SCL=P2^0;sbit RW =P1^1;sbit RS=P1^0;sbit EN=P2^5;uchar code a[]="FM: . ";uchar code b[]="Vol: RSSI: ";uchar code shu[]="0123456789";uchar num ;void delayms(uint x) //延迟程序uint i,j;for(i=x;i>0;i--)for(j=113;j>0;j--);}/*********************************************** 矩阵键盘程序********************************************************************/uchar ScanKey() //矩阵键盘扫描返回值是当前按键数值如没按下则返回值为零{uint x,y;for(x=0;x<4;x++){uchar temp,gaowei;P3=hang[x]; //分行置零temp=P3&0xf0;if(temp!=0xf0){delayms(10);if(temp!=0xf0){gaowei=P3/16; //判断是第几列的按键按下,将数据装入高四位switch(gaowei){case 0xe:y=0; break;case 0xd:y=1; break;case 0xb:y=2; break;case 0x7:y=3; break;}while(temp!=0xf0){temp=P3&0xf0;}return xian[x][y];}}}return 0;}/******************************************************* LCD1602程序************************************************************************/void write_com(unsigned char com)RS=0;P0=com;delayms(5);EN=1;delayms(5);EN=0;}void write_data(unsigned char date){RS=1;P0=date;delayms(5);EN=1;delayms(5);EN=0;}void init_1602(){P0=0xc0;RW =0;EN=0;write_com(0x38); //éè??16*2??ê?£?5*7μ??ó£?8??êy?Y?úwrite_com(0x0c); //éèa??ê?£?2ê?1a±êwrite_com(0x06); //D′ò×?·?oóμ??·ó1write_com(0x01); //??êá?£?êy?Yá?}void DisplayFrq(float Frq) //显示频率{uint F;F=Frq*10;write_com(0x80+3);write_data(shu[F/1000]);delayms(1);write_data(shu[F/100%10]);delayms(1);write_data(shu[F/10%10]);delayms(1);write_com(0x80+7);write_data(shu[F%10]);delayms(1);}void DisplayVol(uint Vol) //显示音量{write_com(0x80+0x40+4);write_data(shu[Vol/10]);delayms(1);write_data(shu[Vol%10]);delayms(1);}void Display_mute() //显示静音{write_com(0x80+0x40+4);write_data('x');delayms(1);write_data('x');delayms(1);}void Display_RSSI(uint RSSI) //显示信号强度{write_com(0x80+0x40+14);write_data(shu[RSSI/10]);delayms(1);write_data(shu[RSSI%10]);delayms(1);}/*----------------------------------------IIC通信程序---------------------------------------------------*/ void IIC_delayms() //用于IIC延时{_nop_();_nop_();_nop_();_nop_();}void OpenIIC() //IIC启动信号{SDA=1;SCL=1;IIC_delayms();SDA=0;IIC_delayms();SCL=0;}void CloseIIC() //IIC停止信号{SCL=0;SDA=0;IIC_delayms();SCL=1;SDA=1;IIC_delayms();}uchar IIC_Wait_Ack(void) //IIC发送字节后等待从机发送响应信{uchar ucErrTime=0;SDA=1;IIC_delayms();SCL=1;IIC_delayms();while(SDA==1){ucErrTime++;if(ucErrTime>250){CloseIIC();return 1;}}SCL=0;return 0;}void IIC_Ack(void) //{SCL=0;SDA=0; //0±íê?ó|′eIIC_delayms();SCL=1;IIC_delayms();SCL=0;}void IIC_NAck(void) //IIC 非应答信号{SCL=0;SDA=1;IIC_delayms();SCL=1;IIC_delayms();SCL=0;}void IICsendByte(uchar txd) //IIC·写一个字节{uchar t;SCL=0;for(t=0;t<8;t++){if(((txd&0x80)>>7)==1)SDA=1;elseSDA=0;txd<<=1;IIC_delayms();SCL=1;IIC_delayms();SCL=0;IIC_delayms();}}uchar IICReadByte(unsigned char ack) //IIC读一个字节{unsigned char i,receive=0;SDA=1; //51单片机讲引脚置高可设为输入引脚for(i=0;i<8;i++ ){SCL=0;IIC_delayms();SCL=1;receive<<=1;if(SDA==1)receive++;IIC_delayms();}if (!ack)IIC_NAck();elseIIC_Ack();return receive;}uint ReadReg(uchar regAddr) //芯片读寄存器{uint buf;OpenIIC();IICsendByte(RDA_WRITE); //发送芯片地址方向为写IIC_Wait_Ack();IICsendByte(regAddr); //发送寄存器地址IIC_Wait_Ack();OpenIIC();IICsendByte(RDA_READ); // 发送芯片地址方向为读IIC_Wait_Ack();buf = IICReadByte(1);buf = buf<<8;buf =buf|IICReadByte(0);CloseIIC();return buf;}void WriteReg(uchar regAddr,uint val) //芯片写寄存器{OpenIIC();IICsendByte(RDA_WRITE); //发送芯片地址方向为写IIC_Wait_Ack();IICsendByte(regAddr); //发送寄存器地址IIC_Wait_Ack();IICsendByte(val>>8);IIC_Wait_Ack();IICsendByte(val&0XFF);IIC_Wait_Ack();CloseIIC();}void Vol_Set(uchar vol) //音量设置0~15{uint temp=0;temp=ReadReg(RDA_R05);temp&=0xfff0;WriteReg(0x05,vol|temp) ;}void Mute_Set(uchar mute) //静音设置1为静音0为不静音{uint temp=0;temp=ReadReg(0X02);if(!mute)temp|=1<<14;else temp&=~(1<<14);WriteReg(0X02,temp) ;}void Bass_Set(uchar bass) //频带设置{uint temp=0;temp=ReadReg(0X02);if(bass)temp|=1<<12;else temp&=~(1<<12);WriteReg(0X02,temp) ;}uchar Rssi_Get(void) //信号强度获取0~63{uint temp=0;temp=ReadReg(0X0B);temp=(temp>>9)&0x7f;return temp;}void Seekth_Set(uint rssi) //自动搜台信号阈值强度0~15 默认为8 数值越低搜到的台越多{uint temp;rssi = rssi & 0xf;temp=ReadReg(0X05);temp&=~(0xf<<8);temp|= rssi<<8;WriteReg(0X05,temp) ;}void Seek_direction(uchar direction) //搜台方向1向上搜索0向下搜索{uint temp;temp=ReadReg(RDA_R02);temp&=~(1<<9);if(direction == 1)temp|= 1<<9;// if(direction == 0)// temp|= 0<<9;WriteReg(0X05,temp) ;}void Freq_Set(uint freq) //频率设置单位是:10KHz 6500~10800{uint temp;uchar spc=0,band=0;uint fbtm,chan;temp=ReadReg(0X03);temp&=0X001F;band=(temp>>2)&0x03;spc=temp&0x03;if(spc==0)spc=10;else if(spc==1)spc=20;else spc=5;if(band==0)fbtm=8700;else if(band==1||band==2)fbtm=7600;else{fbtm=ReadReg(0X53);fbtm*=10;}if(freq<fbtm)return;chan=(freq-fbtm)/spc;chan&=0X3FF;temp|=chan<<6;temp|=1<<4;WriteReg(RDA_R03,temp) ;delayms(20);// while((ReadReg(0X0B)&(1<<7))==0);}unsigned int seek_channel(void) //半自动搜台{unsigned long temp;temp=ReadReg(RDA_R02);temp |= (1<<8);WriteReg(RDA_R02,temp) ; //SEEK位置一使能自动搜台while( (ReadReg(RDA_R0A)&(1<<14)) == 0 ) // 等待STC位置一表示搜索完成{delayms(10); //?óê±10ms}temp = ((ReadReg(RDA_R0A)&0x3FF) * 100000 + 87000000)/10000 ; //获取当前频率return temp; //返回搜到电台频率单位是:10Khz}void FM_enable(uchar flag) //1 使能芯片0 禁用芯片{uint temp;temp=ReadReg(RDA_R02);if(flag ==1 )temp |=1;if(flag == 0)temp &= ~0x1;WriteReg(RDA_R02,temp);}void RDA_Init(void) //RDA3?ê??ˉ{WriteReg(RDA_R02,0x0002); //软复位delayms(30);WriteReg(RDA_R02,0xd081); //?§32.768Khz ?òé÷??μíò? á¢ì?éùSKMODE = 1÷μ?±??μê±í£?1WriteReg(RDA_R03,0x0000); //?μ?êéè?a87MHz £?2100Khz ?μ′??a87M~108MWriteReg(RDA_R04,0x0040); //?ù±WriteReg(RDA_R05,0X8882); //ò?á?éèavol=2 ÷·§?μ?a8FM_enable(1); //??Dé?μ?Seekth_Set(8); //自动搜台信号阈值强度0~15 默认为8 数值越低搜到的台越多}void display_1602(){write_com(0x80);for(num=0;num<34;num++){write_data(a[num]);delayms(5);}write_com(0x80+0x40);for(num=0;num<34;num++){write_data(b[num]);delayms(5);}}void main(){unsigned char Key_num=0,Vol=1,RSSI=0,mute=1;unsigned int RXFreq=8830,time=0;unsigned int Diantai[40]={8830};char Num=0,station=1;unsigned int test=7896;unsigned int temp=10;init_1602();display_1602();RDA_Init(); //RDA5807初始化Freq_Set(8830); //频率设置Vol_Set(2) ;DisplayFrq(88.3);DisplayVol(2); //显示音量while (1){time++;if(time>1000)Display_RSSI(Rssi_Get()); //显示信号强度Key_num=ScanKey();switch(Key_num){case 1: { if(RXFreq==8800)RXFreq=8800; //频率减else RXFreq-=10;Freq_Set(RXFreq);DisplayFrq(RXFreq/100.0);while(0!=ScanKey()); //按键释放break;}case 2:{ if(RXFreq==10800)RXFreq=10800;//频率加else RXFreq+=10;Freq_Set(RXFreq);DisplayFrq(RXFreq/100.0);while(0!=ScanKey()); //按键释放break;}case 5: { //声音减if(Vol==0)Vol=0;elseVol-=1;Vol_Set(Vol);DisplayVol(Vol); //显示音量while(0!=ScanKey()); //按键释放break;}case 6:{ if(Vol==15)Vol=15; //声音加else Vol+=1;Vol_Set(Vol);DisplayVol(Vol); //显示音量while(0!=ScanKey()); //按键释放break;}case 7:{ if(mute==1) //静音{Mute_Set(1);Display_mute(); //显示静音while(0!=ScanKey()); //按键释放mute=0;break;}if(mute==0){Mute_Set(0);DisplayVol(Vol); //取消静音显示音量mute=1;}while(0!=ScanKey());break;}case 9:{ //电台减但是必须先按9进行电台搜索while(0!=ScanKey()); //按键释放Seek_direction(0); //向下搜索RXFreq = seek_channel(); //搜索下一个频道Freq_Set(RXFreq);DisplayFrq(RXFreq/100.0);break;}case 10:{ //电台加但是必须先按11进行电台搜索while(0!=ScanKey()); //按键释放Seek_direction(1); //向上搜索RXFreq = seek_channel(); //搜索下一个频道Freq_Set(RXFreq);DisplayFrq(RXFreq/100.0);break;}default:break;}}}// case 9:{ //电台减但是必须先按11进行电台搜索// if(station==0)break;// if(Num>0)Num-=1;// else Num=station-1;// Freq_Set(Diantai[Num]);// DisplayFrq(Diantai[Num]/100.0);// RXFreq=Diantai[Num];// Display_now(1) ; //显示当前电台号// while(0!=ScanKey()); //按键释放// break;// }// case 10:{ if(station==0)break; //电台加但是必须先按11进行电台搜索// if(Num<(station-1))Num+=1;// else Num=0;// Freq_Set(Diantai[Num]);// DisplayFrq(Diantai[Num]/100.0);// RXFreq=Diantai[Num];// Display_now(Num) ; //显示当前电台号// while(0!=ScanKey()); //按键释放// break;// }//// case 11:{ //自动搜台并且存储按9 或者10 可以上下变换电台。
QPSKSTV0903 TUNER STV6110 驱动设计1.IIC 理论MEGA128 模拟IIC时序控制QPSK 中的STV0903 STV6110STV0903 STV6110 连接图IIC时序理论先看下STV0903写时序图1)起总线先将SCL、SDA拉高,然后维持SCL为高先将SDA拉低参考代码如下:void Start(void){SBI(PORTD,SAA7113_DA TA);SBI(PORTD,SAA7113_CLK);IIC_delay();CBI(PORTD,SAA7113_DA TA);IIC_delay();CBI(PORTD,SAA7113_CLK);IIC_delay();}2)停总线先将SCL、SDA拉低,然后先拉高SCL,维持SCL为高时拉高SDA参考代码:void Stop(void){CBI(PORTD,SAA7113_DA TA);CBI(PORTD,SAA7113_CLK);IIC_delay();SBI(PORTD,SAA7113_CLK);IIC_delay();SBI(PORTD,SAA7113_DA TA);IIC_delay();}3)写总线在写总线时将SDA设置为输出,参考代码:void write_byte(unsigned char data){uchar m,tmp;SBI(SAA7113_DDR,SAA7113_DA TA);for(m = 0; m < 8; m++){if(data & 0x80)SBI(PORTD,SAA7113_DA TA);elseCBI(PORTD,SAA7113_DA TA);IIC_delay();SBI(PORTD,SAA7113_CLK);IIC_delay();data = data<<1;CBI(PORTD,SAA7113_CLK);}IIC_delay();saa7113_ack();IIC_delay();}4)应答应答由被控制芯片回应过来,在此时SDA应该设置为输入等待ACK, 在CLK第九个脉冲时,CLK为高电平,而SDA为一个低电平在表示收到器件的一个ACK应答。
PIC16F1824驱动IIC/I2C接口LCD1602液晶模块前一段时间,做一个显示电路,7段码显示内容太少,LCD1602占用的IO又太多,最后找到一种IIC/I2C接口LCD1602转接板。
T宝上买的LCD1602转接板,有资料,不过是针对Arduino的。
决定自己写程序。
首先得知道从器件地址。
T宝卖家给的地址是0x27(针对Arduino),而单片机使用的时候需要先左移一位,0x4E;测试的时候一直没反应,用示波器看,单片机发送的地址没问题,但转接板没有应答,ACK 一直是高电平,推测还是地址错误;后来搜索发现,PCF8574与PCF8574A的地址是不一样的,而T宝卖的是PCF8574A,给的资料还是PCF8574。
最后确认,从器件PCF8574A地址应该是0x7E;后来发送地址0x7E后,有应答ACK,又搜了写LCD1602的显示程序,稍微改了改,显示成功了;主要的程序如下:MCU:PIC16F1824IIC/I2C接口LCD1602转接板:PCF8574ATmain.c中包含:I2CInit();LCD1602Init();Dip_Single_char(1,5,'A');//********************************************************************// 文件名称: I2C.h// 创建日期: 2016-10-11// 最新更改: 2016-10-11// 描述: I2C初始化//********************************************************************//#define _XTAL_FREQ 2000000 // 延时函数delay_us/ms使用此值#define Slave_Add 0x7E // 从器件地址,PCF8574A,0x7E// PCF8574,0x27,左移1位,0x4E,#define I2C_BPS 0x18 // I2C波特率Fclock = Fosc/((I2C_BPS+1)*4) // 2MHz,20k,0x18#define Idle !(SSP1STATbits.R_nW|(0x1F & SSP1CON2)) // 空闲void I2CInit ( );void I2CStart ( );void I2CStop ( );void ReStart ( );void I2CSendByte(unsigned char I2CSnBy);void WriteCommand(unsigned char Command);void WriteData (unsigned char Data);void LCD1602Init(void);void Dip_Single_char(unsigned char col,unsigned char row,unsigned char sign); void DisDec(unsigned char col_D,unsigned char row_D,unsigned int Temp_k );/*********************************************************************** The End*********************************************************************///********************************************************************// 文件名称: I2C.c// 创建日期: 2016-10-11// 最新更改: 2016-10-11// 描述: I2C初始化//********************************************************************//#include "xc.h"#include "I2C.h"/*********************************************************************** Function name: I2CInit** Descriptions: 注意:必须将SDA、SCL引脚配置为输入引脚,<<DS P293>>** input parameters: 无** output parameters: 无** Returned value: 无**********************************************************************/void I2CInit (void){SSP1STATbits.SMP = 1; // 禁止标准速度模式下的压摆率控制SSP1STATbits.CKE = 0; // 禁止SMBus特定输入SSP1CON1bits.SSPEN = 1; // 使能I2C,并将SDA 和SCL引脚配SSP1CON1bits.SSPM = 0x8; // I2C主模式SSP1ADD = I2C_BPS; // Fclock = Fosc / ((SSP1ADD + 1)*4)}/*********************************************************************** Function name: I2CStart ( )** Descriptions: I2C开始** input parameters: 无** output parameters: 无** Returned value: 无**********************************************************************/void I2CStart ( ){while (!Idle);SSP1CON2bits.SEN = 1; // 在SDA和SCL引脚上发出启动条件,硬件自动清零 while(SSP1CON2bits.SEN); // 启动条件发送完成while(!Idle);}/*********************************************************************** Function name: I2CStop ( )** Descriptions: I2C停止** input parameters: 无** output parameters: 无** Returned value: 无**********************************************************************/void I2CStop(){while (!Idle);SSP1CON2bits.PEN = 1; // 在SDA和SCL引脚上发出停止条件,硬件自动清零 while(SSP1CON2bits.PEN); // 停止条件发送完成while(!Idle);}/*********************************************************************** Function name: ReStart()** Descriptions: I2C ,ReStart** input parameters: 无** output parameters: 无** Returned value: 无**********************************************************************/void ReStart(){while (!Idle);SSP1CON2bits.RSEN = 1; // 在SDA和SCL引脚上发出重复启动条件,硬件自动清零while(SSP1CON2bits.RSEN); // 重复启动条件发送完成while(!Idle);}/*********************************************************************** Function name: I2CSendByte()** Descriptions: SSP1BUF中写入字节** input parameters: I2CSnBy,要发送的数据** output parameters: 无** Returned value: 无**********************************************************************/void I2CSendByte(unsigned char I2CSnBy) {while (!Idle);SSP1BUF = I2CSnBy; // SSP1BUF中写入字节while(!Idle);}/*********************************************************************** Function name:** Descriptions:** input parameters:** output parameters: 无** Returned value: 无**********************************************************************/void WriteCommand(unsigned char Command){I2CStart(); // I2C开始I2CSendByte(Slave_Add); // 从器件地址unsigned char Temp_C;Temp_C = Command & 0xF0;Temp_C |= 0x0C; // P3=1 EN=1 RW=0 RS=0I2CSendByte(Temp_C);Temp_C &= 0xF8; // P3=1 EN=0 RW=0 RS=0I2CSendByte(Temp_C);Temp_C = (Command & 0x0F)<< 4;Temp_C |= 0x0C; // P3=1 EN=1 RW=0 RS=0I2CSendByte(Temp_C);Temp_C &= 0xF8; // P3=1 EN=0 RW=0 RS=0I2CSendByte(Temp_C);I2CStop(); // I2C停止}/********************************************************************* ** Function name:** Descriptions:** input parameters:** output parameters: 无** Returned value: 无**********************************************************************/void WriteData (unsigned char Data){I2CStart(); // I2C开始I2CSendByte(Slave_Add); // 从器件地址unsigned char Temp_D;Temp_D = Data & 0xF0;Temp_D |= 0x0D; // P3=1 EN=1 RW=0 RS=1I2CSendByte(Temp_D);Temp_D &= 0xF9; // P3=1 EN=0 RW=0 RS=1I2CSendByte(Temp_D);Temp_D = (Data & 0x0F)<< 4;Temp_D |= 0x0D; // P3=1 EN=1 RW=0 RS=1I2CSendByte(Temp_D);Temp_D &= 0xF9; // P3=1 EN=0 RW=0 RS=1I2CSendByte(Temp_D);I2CStop(); // I2C停止}/*********************************************************************** Function name: LCD1602Init(void),LCD1602初始化** Descriptions: 写一次,偶尔不能正常显示,重复2次** input parameters:** output parameters: 无** Returned value: 无**********************************************************************/void LCD1602Init(void){__delay_ms(10);WriteCommand(0x33); __delay_ms(5);WriteCommand(0x32); __delay_ms(5);WriteCommand(0x28); __delay_ms(5);WriteCommand(0x0C); __delay_ms(5);WriteCommand(0x06); __delay_ms(5);WriteCommand(0x01); __delay_ms(5); // 清屏__delay_ms(10);WriteCommand(0x33); __delay_ms(5);WriteCommand(0x32); __delay_ms(5);WriteCommand(0x28); __delay_ms(5);WriteCommand(0x0C); __delay_ms(5);WriteCommand(0x06); __delay_ms(5);WriteCommand(0x01); __delay_ms(5); // 清屏}/********************************************************************** Function name: L1602_char(uchar col,uchar row,char sign)** Descriptions: 改变液晶中某位的值,如果要让第一行,第五个字符显示"b" ,调用该函数如,Dip_Single_char(1,5,'A');** input parameters: 行,列,需要输入1602的数据** output parameters: 无** Returned value: 无*********************************************************************/void Dip_Single_char(unsigned char col,unsigned char row,unsigned char sign){ unsigned char a;if(col == 1) a = 0x80;if(col == 2) a = 0xc0;a = a + row - 1;WriteCommand(a);WriteData(sign);}/********************************************************************** Function name: Dip_Single_char** Descriptions: 显示int型数据,5位** input parameters: 行,列,数据** output parameters: 无** Returned value: 无*********************************************************************/void DisDec(unsigned char col_D,unsigned char row_D,unsigned int Temp_k ){if(Temp_k>=65535) Temp_k=65535;unsigned int Temp_Ts;unsigned char Table[5]; // 数字与1602显示码转换Table[0] = Temp_k/10000+48; // 万位Temp_Ts = Temp_k%10000; // 取余,0-9999Table[1] = Temp_Ts/1000+48; // 千位Temp_Ts = Temp_Ts%1000; // 取余,0-999Table[2] = Temp_Ts/100+48; // 百位Temp_Ts = Temp_Ts%100; // 取余,0-99Table[3] = Temp_Ts/10+48; // 十位Table[4] = Temp_Ts%10+48; // 个位unsigned char q;for(q=0;q<5;q++){ // 显示Dip_Single_char(col_D,q+row_D,Table[q]);}}/*********************************************************************** The End*********************************************************************/。
STM32模拟iic驱动eeprom24c128void IIC_Init(void) //IIC初始化函数{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);//使能GPIOB时钟GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOE, &GPIO_InitStructure);GPIO_SetBits(GPIOE,GPIO_Pin_2|GPIO_Pin_3); //PE2,PE3 输出高}void IIC_Start(void) //IIC开始函数{SDA_OUT(); //sda线输出IIC_SDA=1;IIC_SCL=1;delay_us(5);IIC_SDA=0;//START:when CLK is high,DATA change form high to lowdelay_us(5);IIC_SCL=0; //钳住I2C总线,准备发送或接收数据}void IIC_Stop(void) //IIC停止函数{SDA_OUT();//sda线输出IIC_SCL=0;IIC_SDA=0;//STOP:when CLK is high DATA change form low to highdelay_us(5);IIC_SCL=1;IIC_SDA=1;//发送I2C总线结束信号delay_us(5);}u8 IIC_Wait_Ack(void) //等待应答{u8 ucErrTime=0;SDA_IN(); //SDA设置为输入IIC_SDA=1;delay_us(5);IIC_SCL=1;delay_us(1);while(READ_SDA){ucErrTime++;if(ucErrTime>250){IIC_Stop();return 1;}}IIC_SCL=0;//时钟输出0return 0;}void IIC_Ack(void) //SDA输出低电平,IIC应答{IIC_SCL=0;SDA_OUT();IIC_SDA=0;delay_us(2);IIC_SCL=1;delay_us(4);IIC_SCL=0;}void IIC_NAck(void) //SDA输出高电平,IIC非应答{IIC_SCL=0;SDA_OUT();IIC_SDA=1;delay_us(2);IIC_SCL=1;delay_us(4);IIC_SCL=0;}void IIC_Send_Byte(u8 txd) //IIC发送一个字节{u8 t;SDA_OUT(); //数据线输出模式IIC_SCL=0; //拉低时钟开始数据传输for(t=0;t<8;t++){IIC_SDA=(txd&0x80)>>7;txd<<=1;delay_us(5); //对TEA5767这三个延时都是必须的IIC_SCL=1;delay_us(5);IIC_SCL=0;delay_us(5);}}u8 IIC_Read_Byte(unsigned char ack) //IIC读取一个字节{unsigned char i,receive=0;SDA_IN();//SDA设置为输入for(i=0;i<8;i++ ){IIC_SCL=0;delay_us(5);IIC_SCL=1;receive<<=1;if(READ_SDA){receive++;}delay_us(5);}if (!ack)IIC_NAck();//发送nACKelseIIC_Ack(); //发送ACKreturn receive;}void AT24CXX_Init(void) //AT254C128初始化{IIC_Init();}u8 AT24CXX_ReadOneByte(u16 ReadAddr) //AT24C128读取一个字节{u8 temp=0;IIC_Start();IIC_Send_Byte(0XA0); //发送写命令IIC_Wait_Ack();IIC_Send_Byte(ReadAddr>>8);//发送高地址IIC_Wait_Ack();IIC_Send_Byte(ReadAddr%256); //发送低地址IIC_Wait_Ack();IIC_Start();IIC_Send_Byte(0XA1); //进入接收模式IIC_Wait_Ack();temp=IIC_Read_Byte(0);IIC_Stop(); //产生一个停止条件return temp;}void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite) {IIC_Start();IIC_Send_Byte(0XA0); //发送写命令IIC_Wait_Ack();IIC_Send_Byte(WriteAddr>>8);//发送高地址IIC_Wait_Ack();IIC_Send_Byte(WriteAddr%256); //发送低地址IIC_Wait_Ack();IIC_Send_Byte(DataToWrite); //发送字节IIC_Wait_Ack();IIC_Stop();//产生一个停止条件delay_ms(20);}u8 AT24CXX_Check(void){u8 temp;temp=AT24CXX_ReadOneByte(12333);//避免每次开机都写AT24CXXif(temp==0X55){return 0;}else//排除第一次初始化的情况{AT24CXX_WriteOneByte(12333,0X55);temp=AT24CXX_ReadOneByte(12333);if(temp==0X55){return 0;}}return 1;}void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead) {while(NumToRead){*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++);NumToRead--;}}void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite) {while(NumToWrite--){AT24CXX_WriteOneByte(WriteAddr,*pBuffer);WriteAddr++;pBuffer++;}}BY MaiLaoDie。
有关于iic以及ds18b20驱动的解读对于任何一个芯片的使用都离不开对芯片手册的解读,手册中的时序图以及协议必须完全的知晓,才能将芯片正确的使用起来:首先来了解一下使用iic协议的比较常见的AT24C02 这款芯片:通过手册我们可以知道:这款芯片有A0、A1、A2着三个地址管脚,将这三个管脚任意的接上VCC或者是GND都可以构成这款芯片的序列号、在实际的使用中就能够通过总线来进行寻址,然后发送地址,就能对应某一个芯片,并且由此可知,总线上最多可以连接8个这样的芯片,只要改变管脚的三个地址位,就能轻松实现对不同的芯片的控制。
芯片上除了这三个地址管脚之外还有一个WP,是用来写保护的,当这个管脚上是高电平的时候,是没有办法将我们所要的数据写进这款芯片中的,只有当它为低电平的时候才能对这款芯片进行操作。
正常情况下,在使用的时候都是通过硬件电路直接将这个管脚连在GND上。
还有就是Vcc跟Vss分别接上+5V和地,SDA和SCL分别是我们这款芯片的数据位和时钟位,也是我们操作这款芯片的重点。
根据手册的解读,我们可以了解到在时钟线为高电平的时候,数据线要保持不变,如果数据线在时钟线高电平期间,由高电平变为低电平,说明了iic总线协议的开始,如果由低电平变为高电平时,说明了总线协议的结束。
在时钟线为低电平的时候才允许数据线进行跳变并进行传输数据。
在解读时序图的时候底下着两张图很重要。
因为这两张图包含了在写时序图当中的一点细节。
如果这些细节没有处理好的话就会出现芯片不会正常工作的状况。
接下类介绍各个驱动的书写和处理:1、起始信号:由上面的时间表查出来的时间显示,起始信号建立的时间至少是4.7us。
因为时序图是完全按照现实的时间走向画出来的,所以从左向右可以想象成是一个时间轴。
然后看上面这张起始信号的图有可以知道,显示SCL由低电平变为高电平然后保持至少4us的时间。
SDA才开始由高电平变为低电平,在低电平的这段时间查表就可知,这个起始信号保持的时间至少是4us。
Arduino驱动IIC接口(I2C接口)LCD12864液晶模块关键词:Arduino显示,12864液晶模块,中文显示,IIC 接口,I2C接口,12864驱动程序液晶显示模块目前在中国发展已经有30多个年头了,市场上应用最广泛的要属于128*64点阵的显示屏,从类型上分COB,COG及OLED, 稳定性和经济性最好要属于COB工艺的液晶显示模块。
在百度一搜索就可以找到COB简介及工艺COB Chip-on-Board 也称为芯片直接贴装技术,是指将裸芯片直接粘贴在印刷电路板上,然后进行引线键合,再用有机胶将芯片和引线包封保护的工……12864点阵的液晶屏主控芯片一般是ST7920及KS0107+KS0108及KS0086等IC,今天介绍一款我最新发现的一款COB液晶带(RSCG12864B) 拥有I2C接口,内建中文字库(GB2312),ASCII有5*7点阵,6*12点阵,8*16点阵三种之多,可谓目前市场最全,这款液晶屏最出色的要属于可以存储多达2000张图片,可以一般界面只需在电脑上做好BIN格式图片,配合相应的下载工具,就可以存储到液晶模块上。
引脚接线图:序号符号I/O功能描述1<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">GND<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">P<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">电源地2<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.15pt;mso-height-rule:exactly">VDD<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.15pt;mso-height-rule:exactly">P<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm 5.4pt;height:14.15pt;mso-height-rule:exactly">电源3<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">RST<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">I<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">复位信号,低电平有效4<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.15pt;mso-height-rule:exactly">SCL<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.15pt;mso-height-rule:exactly">I<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.15pt;mso-height-rule:exactly">I2C 时钟信号5<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">SDA<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none; border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">I<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">I2C 数据信号6<td width="80" valign="top"style="width:59.7pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">BUSY<td width="72" valign="top"style="width:53.8pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solidblack .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">O<td width="337" valign="top"style="width:252.5pt;border-top:none;border-left:none;border-bottom:solid black 1.0pt;border-right:solid black 1.0pt;mso-border-top-alt:solid black .5pt;mso-border-left-alt:solid black .5pt;mso-border-alt:solid black .5pt;padding:0cm 5.4pt 0cm5.4pt;height:14.2pt;mso-height-rule:exactly">忙信号,高为忙,低为闲。
【Zephyr系统IIC的理解】在嵌入式系统领域,Zephyr系统是一个轻量级、实时操作系统,适用于资源受限的嵌入式设备。
其中的IIC(Inter-Integrated Circuit)通信协议在嵌入式设备中起着至关重要的作用。
本文将从浅入深地介绍Zephyr系统中IIC的基本概念、工作原理和应用场景,以便读者能更全面地了解和掌握这一技术。
一、Zephyr系统中的IIC简介1. IIC通信协议的基本概念IIC是一种多主机、多从机的串行通信总线协议,用于在嵌入式系统中实现各个设备之间的通信和数据传输。
它具有双向传输、串行传输、同步传输等特点,能够在硬件接口简单、连接复杂设备的场景中发挥重要作用。
2. Zephyr系统中的IIC支持Zephyr系统对IIC通信协议提供了完善的支持,包括对IIC总线的初始化、读写操作的封装以及各种IIC设备的驱动程序。
通过Zephyr系统的IIC API,开发人员能够轻松地使用IIC协议实现设备之间的通信和数据交换。
二、Zephyr系统中IIC的工作原理1. IIC总线的工作模式在Zephyr系统中,IIC总线由两根线组成:串行数据线(SDA)和串行时钟线(SCL)。
通过对这两根线的高低电平进行控制,可以实现设备之间的数据传输和通信。
2. Zephyr系统中的IIC驱动程序在Zephyr系统中,每个IIC设备都有对应的驱动程序,用于实现与硬件接口的通信和控制。
开发人员可以通过调用Zephyr系统提供的IIC API,来访问这些驱动程序,从而实现对IIC设备的操作和控制。
三、Zephyr系统中IIC的应用场景1. 传感器数据采集在许多嵌入式系统中,各种传感器通过IIC总线与主控设备连接,将采集到的数据传输给主控设备,以便进行数据处理和分析。
2. 外围设备控制许多外围设备,如显示屏、存储器等,也常常通过IIC总线与主控设备进行通信和控制。
通过Zephyr系统的IIC支持,开发人员能够方便地实现对这些外围设备的控制和操作。
IIC 总线1、IIC 总线简介IIC 总线是Philips 推出的一种串行总线方式,它的全称是Intel Integrate Circuit Bus ,它通过SDA (串行数据线)和SCL (串行时钟线)两根线在连到总线上的器件之间传送信息,并通过软件寻址识别每个器件,而不需要片选线(结合图1说明)。
IIC 总线接口均为开漏或开集电极输出,因此需要为总线增加上拉电阻Rp 。
总线速率越高,总线上拉电阻就越小,对于100Kbit/s 总线速率,通常使用5.1K 欧姆的上拉电阻。
IIC 总线上的通信通常发生在两个器件之间,其中一个是主机另一个是从机,从机和主机均能读和写,ads1110只能作为从机。
2、数据方式IIC 总线有三种数据速率工作方式:标准方式:允许最高100KHz 的时钟频率; 快速方式:允许最高400KHz 的时钟频率; 高速方式:允许最高3.4MHz 的时钟频率。
3、数据传送一条IIC 总线有两条线路构成:SDA 线和SCL 线,SDA 线传送数据,SCL 提供时钟,所用数据以8位为一组在总线上传送。
在数据传送过程中,必须确认数据传送的开始和结束,这通过起始和结束信号识别,开始信号的条件是当时钟为高电平时,数据线从高到低的跳变;结束信号的条件是当时钟为高电平时,数据线从低到高的跳变。
(结合图2说明)SCLSDAIIC 的完整时序图,具体可参考ads1110的datasheet发送起始信号后传送的第一字节数据具有特别的意义,其中前七位为从机地址,最后一位为读写方向位(0表示写,1表示读)。
IIC 总线数据传送时,每传送一个字节数据后都必须有应答信号(A )。
主控器接收数据时,如果要结束通信时,将在停止位之前发送非应答信号( !A )。
IIC 总线是双向的:SDA 用来发送数据和接收数据,当主机从从机中读取数据时,从机驱动数据线,当主机向从机发送数据时,主机驱动数据线,主机总是驱动时钟线。
IIC(Inter-Integrated Circuit)是一种串行通信协议,用于连接微控制器、传感器、存储器和其他外围设备。
以下是IIC标准程序的示例代码,用于在微控制器和外围设备之间进行通信:#include <stdio.h>#include <stdint.h>#include <unistd.h>#include <fcntl.h>#include <sys/ioctl.h>#include <linux/i2c-dev.h>int main(){int file;char *filename = "/dev/i2c-1"; // I2C bus 1 的设备文件路径uint8_t address = 0x50; // I2C 设备的地址char *buffer = malloc(2); // 用于存储从I2C 设备读取的数据的缓冲区// 打开I2C 总线设备文件file = open(filename, O_RDWR);if (file < 0) {perror("Failed to open i2c bus");return -1;}// 设置I2C 总线设备的地址和速率if (ioctl(file, I2C_SLAVE, address) < 0) {perror("Failed to acquire bus access and/or talk to slave");return -1;}// 向I2C 设备写入数据buffer[0] = 0x01; // 要写入的数据的第一个字节buffer[1] = 0x0A; // 要写入的数据的第二个字节int n = write(file, buffer, 2); // 将数据写入I2C 设备if (n < 1) {perror("Write failed");return -1;}// 从I2C 设备读取数据n = read(file, buffer, 1); // 从I2C 设备读取一个字节的数据到缓冲区中if (n < 1) {perror("Read failed");return -1;}printf("Read data: %x\n", buffer[0]); // 打印读取的数据的十六进制表示形式// 关闭I2C 总线设备文件close(file);free(buffer);return 0;}以上代码使用了Linux下的I2C-dev驱动,需要包含`<linux/i2c-dev.h>`头文件。
基于I2C 实时时钟DS3231驱动说明:1Linux的I2C的整体架构Linux的i2c框架中各个部分的关系如图(1)所示:图(1)内核中i2c相关代码可以分为三个层次:●i2c框架:i2c.h和i2c-core.c为i2c框架的主体,提供了核心数据结构的定义、i2c适配器驱动和设备驱动的注册、注销管理,i2c通信方法上层的、与具体适配器无关的代码、检测设备地址的上层代码等;i2c-dev.c用于创建i2c适配器的/dev/i2c/%d设备节点,提供i2c设备访问方法等。
●i2c总线适配器驱动:定义描述具体i2c总线适配器的i2c_adapter数据结构、实现在具体i2c适配器上的i2c总线通信方法,并由i2c_algorithm数据结构进行描述。
●i2c设备驱动:定义描述具体设备的i2c_client和可能的私有数据结构、借助i2c框架的i2c_probe函数实现注册设备的attach_adapter方法、提供设备可能使用的地址范围、以及设备地址检测成功后创建i2c_client数据结构的回调函数。
2I2C驱动相关的数据结构I2C传送信息的数据结构体struct i2c_msg {__u16 addr; /* slave address */__u16 flags;#define I2C_M_TEN 0x10 /* we have a ten bit chip address */#define I2C_M_RD 0x01#define I2C_M_NOSTART 0x4000#define I2C_M_REV_DIR_ADDR 0x2000#define I2C_M_IGNORE_NAK 0x1000#define I2C_M_NO_RD_ACK 0x0800__u16 len; /* msg length */__u8 *buf; /* pointer to msg data */};其中addr 成员是指向器件的地址,flags 是读写标志位,len 是要发送的信息长度,*buf 是发送信息的数据指针,如果是读操作的buf是读到数据的指针。
0.96⼨OLED显⽰屏STM32F103C8T6IIC驱动程序0.96⼨OLED显⽰屏的IIC驱动程序有很多现成的⽰例,但⼤部分编程风格实在是让程序阅读起来很困难,所以本伽椰⼦重新梳理了⼀下驱动程序,使得其更⽅便阅读,具体代码内容如下:1、滴答时钟DRIVE_SYSTICK.h1 #ifndef _DRIVE_SYSTICK_H_2#define _DRIVE_SYSTICK_H_3 #include "stm32f10x.h"45void LibDriveSystickInit(void);6void LibDriveSystickDelay_us(uint32_t Dus);7void LibDriveSystickDelay_ms(uint32_t Dms);8#endifDRIVE_SYSTICK.c1 #include "DRIVE_SYSTICK.h"234/*************************************************5函数名称 : LibDriveSystickInit6功能描述 : 滴答时钟初始化7被调⽤清单 : ⽆8调⽤清单 :9输⼊参数 : ⽆10输出参数 : ⽆11返回参数 : ⽆12其他 : ⽆13*************************************************/14void LibDriveSystickInit(void)15 {16 SysTick->LOAD = 1000;17 SysTick->VAL = 0;18 SysTick->CTRL = 0;19 }2021/*************************************************22函数名称 : LibDriveSystickDelay_us23功能描述 : 滴答时钟微妙级延时24被调⽤清单 : ⽆25调⽤清单 :26输⼊参数 : dus待延时微妙数27输出参数 : ⽆28返回参数 : ⽆29其他 : ⽆30*************************************************/31void LibDriveSystickDelay_us(uint32_t Dus)32 {33if((Dus == 0) || (Dus > 700000))34 {35return;36 }37 SysTick->LOAD = Dus*22-1;38 SysTick->VAL = 0;39 SysTick->CTRL |= 1;4041while((SysTick->CTRL & (1<<16)) == 0);42 SysTick->CTRL = 0;43 }4445/*************************************************46函数名称 : LibDriveSystickDelay_ms47功能描述 :滴答时钟毫秒级延时48被调⽤清单 : ⽆49调⽤清单 :50输⼊参数 : dms待延时毫秒数51输出参数 : ⽆52返回参数 : ⽆53其他 : ⽆54*************************************************/55void LibDriveSystickDelay_ms(uint32_t Dms)56 {57while(Dms >= 700)58 {59 LibDriveSystickDelay_us(700000);60 Dms -= 700;61 }62if(Dms < 700)63 {64 LibDriveSystickDelay_us(Dms*1000);65 }66 }APP_SYSTICK.h1 #ifndef _APP_SYSTICK_H_2#define _APP_SYSTICK_H_3 #include "DRIVE_SYSTICK.h"45void FunAppSystickInit(void);67#endifAPP_SYSTICK.c1 #include "APP_SYSTICK.h"23/*************************************************4函数名称 : FunAppOledDisplayTurn5功能描述 : 屏幕旋转180°6被调⽤清单 : ⽆7调⽤清单 :8输⼊参数 : Mode == 0正常显⽰ Mode == 1反转显⽰9输出参数 : ⽆10返回参数 : ⽆11其他 : ⽆12*************************************************/13void FunAppSystickInit(void)14 {15 LibDriveSystickInit();16 }2、IIC通讯驱动程序DRIVE_I2C2.h1 #ifndef _DRIVE_I2C2_H_2#define _DRIVE_I2C2_H_3 #include "stm32f10x.h"4 #include "DRIVE_SYSTICK.h"56#define SDA_H GPIO_SetBits(GPIOB, GPIO_Pin_11)7#define SDA_L GPIO_ResetBits(GPIOB, GPIO_Pin_11)8#define SCL_H GPIO_SetBits(GPIOB, GPIO_Pin_10)9#define SCL_L GPIO_ResetBits(GPIOB, GPIO_Pin_10)10#define SDA_IN GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11)1112void LibDriveI2c2Init(void);13void LibDriveI2c2Start(void);14void LibDriveI2c2Stop(void);15void LibDriveI2c2SendAck(uint8_t Ack);16void LibDriveI2c2WriteByte(uint8_t Data);17 uint8_t LibDriveI2c2Read(void);18 uint8_t LibDriveI2c2CheckAck(void);1920#endifDRIVE_I2C2.c1 #include "DRIVE_I2C2.h"23/*************************************************4函数名称 : LibDriveI2c2Init5功能描述 : I2C2初始化6被调⽤清单 : ⽆7调⽤清单 :8输⼊参数 : ⽆9输出参数 : ⽆10返回参数 : ⽆11其他 : ⽆12*************************************************/13void LibDriveI2c2Init(void)14 {15 GPIO_InitTypeDef GPIO_InitStruct;16 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); 1718 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;19 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;20 GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;21 GPIO_Init(GPIOB, &GPIO_InitStruct);22 }2324/*************************************************25函数名称 : LibDriveI2c2Start26功能描述 : I2C2开始信号27被调⽤清单 : ⽆28调⽤清单 :29输⼊参数 : ⽆30输出参数 : ⽆31返回参数 : ⽆32其他 : ⽆33*************************************************/34void LibDriveI2c2Start(void)35 {36 SCL_L;37 SDA_H;3839 SCL_H;40 LibDriveSystickDelay_us(5);41 SDA_L;42 LibDriveSystickDelay_us(5);43 SCL_L;44 }4546/*************************************************47函数名称 : LibDriveI2c2Stop48功能描述 : I2C2停⽌信号49被调⽤清单 : ⽆50调⽤清单 :51输⼊参数 : ⽆52输出参数 : ⽆53返回参数 : ⽆54其他 : ⽆55*************************************************/56void LibDriveI2c2Stop(void)57 {58 SCL_L;59 SDA_L;6061 SCL_H;62 LibDriveSystickDelay_us(5);63 SDA_H;64 LibDriveSystickDelay_us(5);65 }6667/*************************************************68函数名称 : LibDriveI2c2SendAck69功能描述 : I2C2发送回复70被调⽤清单 : ⽆71调⽤清单 :72输⼊参数 : Ack 回复状态73输出参数 : ⽆74返回参数 : ⽆75其他 : ⽆76*************************************************/77void LibDriveI2c2SendAck(uint8_t Ack)78 {79if (Ack) //不应答80 {81 SCL_L;82 LibDriveSystickDelay_us(5);83 SDA_H;84 LibDriveSystickDelay_us(1);85 SCL_H;86 LibDriveSystickDelay_us(5);87 }88else if (Ack == 0) //应答89 {90 SCL_L;91 LibDriveSystickDelay_us(5);92 SDA_L;93 LibDriveSystickDelay_us(1);94 SCL_H;95 LibDriveSystickDelay_us(5);96 }97 SCL_L;98 }99100/*************************************************101函数名称 : LibDriveI2c2WriteByte102功能描述 : I2C2写⼀个字节103被调⽤清单 : ⽆104调⽤清单 :105输⼊参数 : Data 待发送数据106输出参数 : ⽆107返回参数 : ⽆108其他 : ⽆109*************************************************/110void LibDriveI2c2WriteByte(uint8_t Data)111 {112 uint8_t localIte = 0;113for (localIte = 0; localIte < 8; localIte++)114 {115 SCL_L; //可以改变数据线116 LibDriveSystickDelay_us(5);117if (Data & 0x80)118 {119 SDA_H;120 }121else122 {123 SDA_L;124 }125 LibDriveSystickDelay_us(1);126 SCL_H; //从机时钟线拉⾼从机才可以读此位数据127 LibDriveSystickDelay_us(5);128 Data = Data << 1;129 }130 SCL_L; //安全131 }132133/*************************************************134函数名称 : LibDriveI2c2Read135功能描述 : I2C2读取数据136被调⽤清单 : ⽆137调⽤清单 :138输⼊参数 : ⽆139输出参数 : ⽆140返回参数 : 所读取到的数据(⼀个字节)141其他 : ⽆142*************************************************/143 uint8_t LibDriveI2c2Read(void)144 {145 uint8_t localData = 0;146 uint8_t localIte = 0;147148/*把数线的模式改为输⼊模式*/149 SCL_L; //可以改变数据线150 SDA_H; //输⼊模式151152/*接收⼋位数据*/153for (localIte = 0; localIte < 8; localIte++)154 {155 SCL_L; //拉低时钟线,从机发送⼀个位数据156 LibDriveSystickDelay_us(5);157 SCL_H; //主机读158 LibDriveSystickDelay_us(5);159 localData = localData << 1;160if (SDA_IN)161 {162 localData = localData | 0x01;163 }164 }165 SCL_L; //安全166return localData;167 }168169/*************************************************170函数名称 : LibDriveI2c2CheckAck171功能描述 : I2C2检查回复状态172被调⽤清单 : ⽆173调⽤清单 :174输⼊参数 : ⽆175输出参数 : ⽆176返回参数 : 应答返回1 ⽆应答放回0177其他 : ⽆178*************************************************/179 uint8_t LibDriveI2c2CheckAck(void)180 {181 uint8_t Ack = 0;182/*将数据线的模式改变为输⼊模式*/183 SCL_L;184 SDA_H;185/*检测应答位信号*/186 SCL_L; //从机可以发送应答信号/不应答信号187 LibDriveSystickDelay_us(5);188189 SCL_H; //主机可以读应答信号190 LibDriveSystickDelay_us(5);191if (SDA_IN) //应答192 {193 Ack = 1;194 }195 SCL_L; //安全196return Ack;197 }3、OLED驱动程序APP_OLED.h1 #ifndef _APP_OLED_H_2#define _APP_OLED_H_3 #include "DRIVE_I2C2.h"4 #include <stdlib.h>56#define OLED_CMD 0//写命令7#define OLED_DATA 1//写数据89void FunAppOledInit(void);10void FunAppOledWriteByte(uint8_t Data, uint8_t Mode);11void FunAppOledDisPlayOn(void);12void FunAppOledDisPlayOff(void);13void FunAppOledClear(void);14void FunAppOledRefresh(void);15void FunAppOledDrawPoint(uint8_t X, uint8_t Y);16void FunAppOledClearPoint(uint8_t X, uint8_t Y);17void FunAppOledDrawLine(uint8_t X1, uint8_t Y1, uint8_t X2, uint8_t Y2);18void FunAppOledDrawCircle(uint8_t X, uint8_t Y, uint8_t R);19void FunAppOledShowChar(uint8_t X, uint8_t Y, uint8_t Chr, uint8_t Size); 20void FunAppOledShowString(uint8_t X, uint8_t Y, uint8_t * Chr, uint8_t Size);21void FunAppOledShowNum(uint8_t X, uint8_t Y, uint32_t Num, uint8_t Len, uint8_t Size);22void FunAppOledShowChinese(uint8_t X, uint8_t Y, uint8_t Num, uint8_t Size);23void FunAppOledScrollDisplay(uint8_t Num, uint8_t Space);24void FunAppOledWriteBP(uint8_t X, uint8_t Y);25void FunAppOledShowPicture(uint8_t X1, uint8_t Y1, uint8_t X2, uint8_t Y2, uint8_t *Bmp);26void FunAppOledColorTurn(uint8_t Mode);27void FunAppOledDisplayTurn(uint8_t Mode);28 uint32_t FunAppOledPow(uint8_t Num, uint8_t Index);29#endifAPP_OLED.c1 #include "APP_OLED.h"2 #include "OLED_FONT.h"34static uint8_t OLED_GRAM[144][8];56/*************************************************7函数名称 : FunAppOledInit8功能描述 : OLED初始化9被调⽤清单 : ⽆10调⽤清单 :11输⼊参数 : ⽆12输出参数 : ⽆13返回参数 : ⽆14其他 : ⽆15*************************************************/16void FunAppOledInit(void)17 {18 LibDriveI2c2Init();19 LibDriveSystickDelay_ms(100);20 FunAppOledWriteByte(0xAE,OLED_CMD);//--turn off oled panel21 FunAppOledWriteByte(0x00,OLED_CMD);//---set low column address22 FunAppOledWriteByte(0x10,OLED_CMD);//---set high column address23 FunAppOledWriteByte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)24 FunAppOledWriteByte(0x81,OLED_CMD);//--set contrast control register25 FunAppOledWriteByte(0xCF,OLED_CMD);// Set SEG Output Current Brightness26 FunAppOledWriteByte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常27 FunAppOledWriteByte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常28 FunAppOledWriteByte(0xA6,OLED_CMD);//--set normal display29 FunAppOledWriteByte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)30 FunAppOledWriteByte(0x3f,OLED_CMD);//--1/64 duty31 FunAppOledWriteByte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)32 FunAppOledWriteByte(0x00,OLED_CMD);//-not offset33 FunAppOledWriteByte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency34 FunAppOledWriteByte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec35 FunAppOledWriteByte(0xD9,OLED_CMD);//--set pre-charge period36 FunAppOledWriteByte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock37 FunAppOledWriteByte(0xDA,OLED_CMD);//--set com pins hardware configuration38 FunAppOledWriteByte(0x12,OLED_CMD);39 FunAppOledWriteByte(0xDB,OLED_CMD);//--set vcomh40 FunAppOledWriteByte(0x40,OLED_CMD);//Set VCOM Deselect Level41 FunAppOledWriteByte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)42 FunAppOledWriteByte(0x02,OLED_CMD);//43 FunAppOledWriteByte(0x8D,OLED_CMD);//--set Charge Pump enable/disable44 FunAppOledWriteByte(0x14,OLED_CMD);//--set(0x10) disable45 FunAppOledWriteByte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)46 FunAppOledWriteByte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)47 FunAppOledWriteByte(0xAF,OLED_CMD);48 FunAppOledClear();49 }5051/*************************************************52函数名称 : FunAppOledWriteByte53功能描述 : OLED写⼊⼀字节54被调⽤清单 : ⽆55调⽤清单 :56输⼊参数 : Data待写⼊数据,Mode数据写⼊模式,为0为写指令为1为写数据57输出参数 : ⽆58返回参数 : ⽆59其他 : ⽆60*************************************************/61void FunAppOledWriteByte(uint8_t Data, uint8_t Mode)62 {63 uint8_t localAck = 0;64 LibDriveI2c2Start();65 LibDriveI2c2WriteByte(0x78);66 localAck = LibDriveI2c2CheckAck();67if(localAck)68 {69 LibDriveI2c2Stop();70 }71if(Mode)72 {73 LibDriveI2c2WriteByte(0x40);74 }75else76 {77 LibDriveI2c2WriteByte(0x00);78 }7980 localAck = LibDriveI2c2CheckAck();81if(localAck)82 {83 LibDriveI2c2Stop();84 }85 LibDriveI2c2WriteByte(Data);8687 localAck = LibDriveI2c2CheckAck();88if(localAck)89 {90 LibDriveI2c2Stop();91 }92 LibDriveI2c2Stop();93 }9495/*************************************************96函数名称 : FunAppOledDisPlayOn97功能描述 : 开启OLED显⽰98被调⽤清单 : ⽆99调⽤清单 :100输⼊参数 : ⽆101输出参数 : ⽆102返回参数 : ⽆103其他 : ⽆104*************************************************/105void FunAppOledDisPlayOn(void)106 {107 FunAppOledWriteByte(0x8D, OLED_CMD);//电荷泵使能108 FunAppOledWriteByte(0x14, OLED_CMD);//开启电荷泵109 FunAppOledWriteByte(0xAE, OLED_CMD);//点亮屏幕110 }111112/*************************************************113函数名称 : FunAppOledDisPlayOn114功能描述 : 关闭OLED显⽰115被调⽤清单 : ⽆116调⽤清单 :117输⼊参数 : ⽆118输出参数 : ⽆119返回参数 : ⽆120其他 : ⽆121*************************************************/122void FunAppOledDisPlayOff(void)123 {124 FunAppOledWriteByte(0x8D, OLED_CMD);//电荷泵使能125 FunAppOledWriteByte(0x10, OLED_CMD);//关闭电荷泵126 FunAppOledWriteByte(0xAF, OLED_CMD);//关闭屏幕127 }128129/*************************************************130函数名称 : FunAppOledRefresh131功能描述 : 更新显⽰132被调⽤清单 : ⽆133调⽤清单 :134输⼊参数 : ⽆135输出参数 : ⽆136返回参数 : ⽆137其他 : ⽆138*************************************************/139void FunAppOledRefresh(void)140 {141 uint8_t localIte = 0;142 uint8_t localNum = 0;143144for (localIte = 0; localIte < 8; localIte++)145 {146 FunAppOledWriteByte(0xB0 + localIte, OLED_CMD);147 FunAppOledWriteByte(0x00 , OLED_CMD);148 FunAppOledWriteByte(0x10 , OLED_CMD);149for (localNum = 0; localNum < 128; localNum++)150 {151 FunAppOledWriteByte(OLED_GRAM[localNum][localIte], OLED_DATA); 152 }153 }154 }155156/*************************************************157函数名称 : FunAppOledClear158功能描述 : 清屏159被调⽤清单 : ⽆160调⽤清单 :161输⼊参数 : ⽆162输出参数 : ⽆163返回参数 : ⽆164其他 : ⽆165*************************************************/166void FunAppOledClear(void)167 {168 uint8_t localIte = 0;169 uint8_t localNum = 0;170171for (localIte = 0; localIte < 8; localIte++)172 {173for (localNum = 0; localNum < 128; localNum++)174 {175 OLED_GRAM[localNum][localIte] = 0;176 }177 }178 FunAppOledRefresh();179 }180181/*************************************************182函数名称 : FunAppOledDrawPoint183功能描述 : 画点184被调⽤清单 : ⽆185调⽤清单 :186输⼊参数 : X(0 ~ 127) , Y(0 ~ 63)187输出参数 : ⽆188返回参数 : ⽆189其他 : ⽆190*************************************************/191void FunAppOledDrawPoint(uint8_t X, uint8_t Y)192 {193 uint8_t localI = 0;194 uint8_t localM = 0;195 uint8_t localN = 0;196197 localI = Y / 8;198 localM = Y % 8;199 localN = 1 << localM;200 OLED_GRAM[X][localI] |= localN;201 }202203/*************************************************204函数名称 : FunAppOledClearPoint205功能描述 : 清除⼀个点206被调⽤清单 : ⽆207调⽤清单 :208输⼊参数 : X(0 ~ 127) , Y(0 ~ 63)209输出参数 : ⽆210返回参数 : ⽆211其他 : ⽆212*************************************************/213void FunAppOledClearPoint(uint8_t X, uint8_t Y)214 {215 uint8_t localI = 0;216 uint8_t localM = 0;217 uint8_t localN = 0;218219 localI = Y / 8;220 localM = Y % 8;221 localN = 1 << localM;222223 OLED_GRAM[X][localI] = ~OLED_GRAM[X][localI];224 OLED_GRAM[X][localI] |= localN;225 OLED_GRAM[X][localI] = ~OLED_GRAM[X][localI];226 }227228/*************************************************229函数名称 : FunAppOledDrawLine230功能描述 : 画线231被调⽤清单 : ⽆232调⽤清单 :233输⼊参数 : X(0 ~ 127) , Y(0 ~ 63) (X1 , Y1)第⼀个点坐标(X2 , Y2)第⼆个点坐标234输出参数 : ⽆235返回参数 : ⽆236其他 : ⽆237*************************************************/238void FunAppOledDrawLine(uint8_t X1, uint8_t Y1, uint8_t X2, uint8_t Y2)239 {240 uint8_t localIte = 0;241 uint8_t localK0 = 0;242 uint8_t localK1 = 0;243 uint8_t localK2 = 0;244245if ((X2 > 128)|| (Y2 > 64) || (X1 > X2) || (Y1 > Y2))246 {247return ;248 }249250if (X1 == X2) //竖线251 {252for (localIte = 0; localIte < (Y2 - Y1); localIte++)253 {254 FunAppOledDrawPoint(X1, (Y1 + localIte));255 }256 }257else if (Y1 == Y2)//横线258 {259for (localIte = 0; localIte < (X2 - X1); localIte++)260 {261 FunAppOledDrawPoint((X1 + localIte), Y1);262 }263 }264else//斜线265 {266 localK0 = Y2 - Y1;267 localK1 = X2 - X1;268 localK2 = (localK0 * 10) / localK1;269for (localIte = 0; localIte < (X2 - X1); localIte++)270 {271 FunAppOledDrawPoint((X1 + localIte), (Y1 + ((localIte * localK2) / 10)));272 }273 }274 }275276/*************************************************277函数名称 : FunAppOledDrawCircle278功能描述 : 画圆279被调⽤清单 : ⽆280调⽤清单 :281输⼊参数 : X(0 ~ 127) , Y(0 ~ 63) (X , Y)圆⼼坐标 R半径282输出参数 : ⽆283返回参数 : ⽆284其他 : ⽆285*************************************************/286void FunAppOledDrawCircle(uint8_t X, uint8_t Y, uint8_t R)287 {288int localA = 0;289int localB = 0;290int localN = 0;291292 localB = R;293while((2 * localB * localB) >= (R * R))294 {295 FunAppOledDrawPoint(X + localA, Y - localB);296 FunAppOledDrawPoint(X - localA, Y - localB);297 FunAppOledDrawPoint(X - localA, Y + localB);298 FunAppOledDrawPoint(X + localA, Y + localB);299300 FunAppOledDrawPoint(X + localB, Y - localA);301 FunAppOledDrawPoint(X - localB, Y - localA);302 FunAppOledDrawPoint(X - localB, Y + localA);303 FunAppOledDrawPoint(X + localB, Y + localA);304305 localA++;306 localN = ((localA * localA) + (localB * localB)) - (R * R);//计算画的点离圆⼼的距离307if (localN > 0 )308 {309 localA--;310 localB--;311 }312 }313 }314315/*************************************************316函数名称 : FunAppOledShowChar317功能描述 : 显⽰⼀个字符318被调⽤清单 : ⽆319调⽤清单 :320输⼊参数 : X(0 ~ 127) , Y(0 ~ 63) (X , Y)起点坐标 Chr待显⽰字符 Size字体⼤⼩321输出参数 : ⽆322返回参数 : ⽆323其他 : ⽆324*************************************************/325void FunAppOledShowChar(uint8_t X, uint8_t Y, uint8_t Chr, uint8_t Size)326 {327 uint8_t localIte = 0;328 uint8_t localIte1 = 0;329 uint8_t localTemp = 0;330 uint8_t localSize = 0;331 uint8_t localChr = 0;332 uint8_t localY = 0;333334 localY = Y;335 localSize = ((Size / 8) + ((Size % 8) ? 1 : 0)) * (Size / 2);//得到字体⼀个字符对应点阵集所占字节数336 localChr = Chr - ''; //计算偏移后的值337for (localIte = 0; localIte < localSize; localIte++)338 {339if (Size == 12)340 {341 localTemp = asc2_1206[localChr][localIte];//调⽤1206字体342 }343else if (Size == 16)344 {345 localTemp = asc2_1608[localChr][localIte];//调⽤1608字体346 }347else if (Size == 24)348 {349 localTemp = asc2_2412[localChr][localIte];//调⽤2412字体350 }351else352 {353return ;354 }355356for (localIte1 = 0; localIte1 < 8; localIte1++)357 {358if (localTemp & 0x80)359 {360 FunAppOledDrawPoint(X, Y);361 }362else363 {364 FunAppOledClearPoint(X, Y);365 }366 localTemp <<= 1;367 Y++;368if ((Y - localY) == Size)369 {370 Y = localY;371 X++;372break;373 }374 }375 }376 }377378/*************************************************379函数名称 : FunAppOledShowString380功能描述 : 显⽰字符串381被调⽤清单 : ⽆382调⽤清单 :383输⼊参数 : X(0 ~ 127) , Y(0 ~ 63) (X , Y)起点坐标 Chr待显⽰字符串 Size字体⼤⼩384输出参数 : ⽆385返回参数 : ⽆386其他 : ⽆387*************************************************/388void FunAppOledShowString(uint8_t X, uint8_t Y, uint8_t * Chr, uint8_t Size)389 {390while((*Chr >= '') && (*Chr <= '~'))//判断是不是⾮法字符391 {392 FunAppOledShowChar(X, Y, *Chr, Size);393 X += Size / 2;394if (X > (128 - Size)) //换⾏395 {396 X = 0;397 Y += 2;398 }399 Chr++;400 }401 }402403/*************************************************404函数名称 : FunAppOledPow405功能描述 : 计算⼀个数据的次⽅406被调⽤清单 : ⽆407调⽤清单 :408输⼊参数 : Num底数,Index指数409输出参数 : ⽆410返回参数 : 计算后的值411其他 : ⽆412*************************************************/413 uint32_t FunAppOledPow(uint8_t Num, uint8_t Index)414 {415 uint32_t localRes = 1;416while(Index--)417 {418 localRes *= Num;419 }420return localRes;421 }422423/*************************************************424函数名称 : FunAppOledShowNum425功能描述 : 显⽰数字426被调⽤清单 : ⽆427调⽤清单 :428输⼊参数 : (X , Y)起点坐标 Len数字的位数 Size字体⼤⼩429输出参数 : ⽆430返回参数 : ⽆431其他 : ⽆432*************************************************/433void FunAppOledShowNum(uint8_t X, uint8_t Y, uint32_t Num, uint8_t Len, uint8_t Size) 434 {435 uint8_t localIte = 0;436 uint8_t localTemp = 0;437438for (localIte = 0; localIte < Len; localIte++)439 {440 localTemp = (Num / FunAppOledPow(10, Len - localIte - 1)) % 10;441if (localTemp == 0)442 {443 FunAppOledShowChar((X + (Size / 2) * localIte), Y, '0', Size);444 }445else446 {447 FunAppOledShowChar((X + (Size / 2) * localIte), Y, (localTemp + '0'), Size); 448 }449 }450 }451452/*************************************************453函数名称 : FunAppOledShowChinese454功能描述 : 显⽰汉字455被调⽤清单 : ⽆456调⽤清单 :457输⼊参数 : (X , Y)起点坐标 Num汉字对应序号 Size字体⼤⼩458输出参数 : ⽆459返回参数 : ⽆460其他 : ⽆461*************************************************/462void FunAppOledShowChinese(uint8_t X, uint8_t Y, uint8_t Num, uint8_t Size)463 {464 uint8_t localIte0 = 0;465 uint8_t localIte1 = 0;466 uint8_t localCount = 0;467 uint8_t localTemp = 0;468 uint8_t localChr = 0;469 uint8_t localX = 0;470 uint8_t localY = 0;471 uint8_t localSize = 0;472473 localX = X;474 localY = Y;475 localSize = Size / 8;476477while (localSize--)478 {479 localChr = (Num * Size / 8) + localCount;480 localCount++;481482for (localIte0 = 0; localIte0 < Size; localIte0++)483 {484if (Size == 16)485 {486 localTemp = Hzk0[localChr][localIte0]; //调⽤16*16字体487 }488else if (Size == 24)489 {490 localTemp = Hzk2[localChr][localIte0]; //调⽤24*24字体491 }492else if (Size == 32)493 {494 localTemp = Hzk3[localChr][localIte0]; //调⽤32*32字体495 }496else if (Size == 64)497 {498 localTemp = Hzk4[localChr][localIte0]; //调⽤64*64字体499 }500else501 {502return ;503 }504505for (localIte1 = 0; localIte1 < 8; localIte1++)506 {507if (localTemp & 0x01)508 {509 FunAppOledDrawPoint(X, Y);510 }511else512 {513 FunAppOledClearPoint(X, Y);514 }515 localTemp >>= 1;516 Y++;517 }518 X++;519if ((X - localX) == Size)520 {521 X = localX;522 localY = localY + 8;523 }524 Y = localY;525 }526 }527 }528529/*************************************************530函数名称 : FunAppOledScrollDisplay531功能描述 : 左移显⽰532被调⽤清单 : ⽆533调⽤清单 :534输⼊参数 : Num显⽰汉字的个数,Space每⼀遍显⽰的间隔535输出参数 : ⽆536返回参数 : ⽆537其他 : ⽆538*************************************************/539void FunAppOledScrollDisplay(uint8_t Num, uint8_t Space)540 {541 uint8_t localIte0 = 0;542 uint8_t localIte1 = 0;543 uint8_t localIte2 = 0;544 uint8_t localIte3 = 0;545 uint8_t localIte4 = 0;546 uint8_t localNum = 0;547 uint8_t localTemp = 0;548549while (1)550 {551if (localNum == 0)552 {553 FunAppOledShowChinese(128, 24, localTemp, 16);//写⼊⼀个汉字保存在OLED_GRAM中554 localTemp++;555 }556557if (localTemp == Num)558 {559for (localIte0 = 0; localIte0 < (16 * Space); localIte0++)//显⽰间隔560 {561for (localIte1 = 0; localIte1 < 144; localIte1++)562 {563for (localIte2 = 0; localIte2 < 8; localIte2++)564 {565 OLED_GRAM[localIte1 - 1][localIte2] = OLED_GRAM[localIte1][localIte2]; 566 }567 }568 FunAppOledRefresh();569 }570 localTemp = 0;571 }572 localNum++;573if (localNum == 16)574 {575 localNum = 0;576 }577for (localIte3 = 0; localIte3 < 144; localIte3++) //左移578 {579for (localIte4 = 0; localIte4 < 8; localIte4++)580 {581 OLED_GRAM[localIte3 - 1][localIte4] = OLED_GRAM[localIte3][localIte4];582 }583 }584 FunAppOledRefresh();585 }586 }587588/*************************************************589函数名称 : FunAppOledWriteBP590功能描述 : 配置写⼊数据的起始位置591被调⽤清单 : ⽆592调⽤清单 :593输⼊参数 : (X , Y)起始位置坐标594输出参数 : ⽆595返回参数 : ⽆596其他 : ⽆597*************************************************/598void FunAppOledWriteBP(uint8_t X, uint8_t Y)599 {600 FunAppOledWriteByte((0xB0 + Y), OLED_CMD);601 FunAppOledWriteByte(((X & 0xF0) >> 4) | 0x10, OLED_CMD);602 FunAppOledWriteByte((X & 0x0F) | 0x01, OLED_CMD);603 }604605/*************************************************606函数名称 : FunAppOledShowPicture607功能描述 : 显⽰图⽚608被调⽤清单 : ⽆609调⽤清单 :610输⼊参数 : (X1 , Y1)起始坐标 (X2 , Y2)终点坐标 Bmp要写⼊的图⽚数组611输出参数 : ⽆612返回参数 : ⽆613其他 : ⽆614*************************************************/615void FunAppOledShowPicture(uint8_t X1, uint8_t Y1, uint8_t X2, uint8_t Y2, uint8_t *Bmp) 616 {617 uint32_t localIte0 = 0;618 uint8_t localX = 0;619 uint8_t localY = 0;620621if ((localY % 8) == 0)622 {623 localY = 0;624 }625else626 {627 localY += 1;628 }629630for (localY = Y1; localY < Y2; localY++)631 {632 FunAppOledWriteBP(X1, localY);633for (localX = X1; localX < X2; localX++)634 {635 FunAppOledWriteByte(Bmp[localIte0], OLED_DATA);636 localIte0++;637 }638 }639 }640641/*************************************************642函数名称 : FunAppOledColorTurn643功能描述 : 反显函数644被调⽤清单 : ⽆645调⽤清单 :646输⼊参数 : Mode == 0正常显⽰, Mode == 1反⾊显⽰647输出参数 : ⽆648返回参数 : ⽆649其他 : ⽆650*************************************************/651void FunAppOledColorTurn(uint8_t Mode)652 {653if (Mode == 0)654 {655 FunAppOledWriteByte(0xA6, OLED_CMD);//正常显⽰656 }657658if (Mode == 1)659 {660 FunAppOledWriteByte(0xA7, OLED_CMD);//反⾊显⽰661 }662 }663664/*************************************************665函数名称 : FunAppOledDisplayTurn666功能描述 : 屏幕旋转180°667被调⽤清单 : ⽆668调⽤清单 :669输⼊参数 : Mode == 0正常显⽰ Mode == 1反转显⽰670输出参数 : ⽆671返回参数 : ⽆672其他 : ⽆673*************************************************/674void FunAppOledDisplayTurn(uint8_t Mode)675 {676if (Mode == 0)677 {678 FunAppOledWriteByte(0xC8, OLED_CMD);//正常显⽰679 FunAppOledWriteByte(0xA1, OLED_CMD);680 }681682if (Mode == 1)683 {684 FunAppOledWriteByte(0xC0, OLED_CMD);//反转显⽰685 FunAppOledWriteByte(0xA0, OLED_CMD);686 }687 }4、字体OLED_FONT.h1/************************************************************2 * Copyright (C) 2021 , 伽椰⼦真可爱3 * All right reserved.4 * ⽂件名称:OLED_FONT.h5 * 作者:⾼弟(GaoDi)6 * 原始版本:V1.07 * 创建⽇期:2022/1/108 * ⽂件描述:OLED字体9 * 函数列表:10 *11 * 历史:12 * <作者> <时间> <版本> <功能描述>13 *14 * **********************************************************/15 #ifndef _OLED_FONT_H_16#define _OLED_FONT_H_1718//常⽤ASCII表19//偏移量3220//ASCII字符集21//偏移量3222//⼤⼩:12*623/************************************6*8的点阵************************************/24//12*12 ASCII字符集点阵25const unsigned char asc2_1206[95][12]={26 {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/27 {0x00,0x00,0x00,0x00,0x3F,0x40,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/28 {0x00,0x00,0x30,0x00,0x40,0x00,0x30,0x00,0x40,0x00,0x00,0x00},/*""",2*/29 {0x09,0x00,0x0B,0xC0,0x3D,0x00,0x0B,0xC0,0x3D,0x00,0x09,0x00},/*"#",3*/30 {0x18,0xC0,0x24,0x40,0x7F,0xE0,0x22,0x40,0x31,0x80,0x00,0x00},/*"$",4*/31 {0x18,0x00,0x24,0xC0,0x1B,0x00,0x0D,0x80,0x32,0x40,0x01,0x80},/*"%",5*/32 {0x03,0x80,0x1C,0x40,0x27,0x40,0x1C,0x80,0x07,0x40,0x00,0x40},/*"&",6*/33 {0x10,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/。
IIC通信详解(1)概述I2C(Inter-Integrated Circuit BUS) 集成电路总线,该总线由NXP(原PHILIPS)公司设计,多⽤于主控制器和从器件间的主从通信,在⼩数据量场合使⽤,传输距离短,任意时刻只能有⼀个主机等特性。
经常IIC和SPI接⼝被认为指定是⼀种硬件设备,但其实这样的说法是不尽准确的,严格的说他们都是⼈们所定义的软硬结合体,分为物理层(四线结构)和协议层(主机,从机,时钟极性,时钟相位)。
IIC,SPI的区别不仅在与物理层,IIC⽐SPI有着⼀套更为复杂的协议层定义。
下⾯来分别说明⼀下IIC的物理层和协议层。
(2)IIC的物理层a.只要求两条总线线路,⼀条是串⾏数据线SDA,⼀条是串⾏时钟线SCL。
(IIC是半双⼯,⽽不是全双⼯)。
b.每个连接到总线的器件都可以通过唯⼀的地址和其它器件通信,主机/从机⾓⾊和地址可配置,主机可以作为主机发送器和主机接收器。
c.IIC是真正的多主机总线,(⽽这个SPI在每次通信前都需要把主机定死,⽽IIC可以在通讯过程中,改变主机),如果两个或更多的主机同时请求总线,可以通过冲突检测和仲裁防⽌总线数据被破坏。
d.传输速率在标准模式下可以达到100kb/s,快速模式下可以达到400kb/s。
e.连接到总线的IC数量只是受到总线的最⼤负载电容400pf限制。
⼀个典型的IIC接⼝如下图(1)所⽰图(1)(3)IIC的协议层IIC的协议层才是掌握IIC的关键。
现在简单概括如下:a.数据的有效性在时钟的⾼电平周期内,SDA线上的数据必须保持稳定,数据线仅可以在时钟SCL为低电平时改变。
如图(2)所⽰:图(2)b.起始和结束条件起始条件:当SCL为⾼电平的时候,SDA线上由⾼到低的跳变被定义为起始条件,结束条件:当SCL为⾼电平的时候,SDA线上由低到⾼的跳变被定义为停⽌条件,要注意起始和终⽌信号都是由主机发出的,连接到I2C总线上的器件,若具有I2C总线的硬件接⼝,则很容易检测到起始和终⽌信号。
IIC设备驱动程序IIC设备是一种通过IIC总线连接的设备,由于其简单性,被广泛引用于电子系统中。
在现代电子系统中,有很多的IIC设备需要进行相互之间通信IIC总线是由PHILIPS公司开发的两线式串行总线,用于连接微处理器和外部IIC设备。
IIC设备产生于20世纪80年代,最初专用与音频和视频设备,现在在各种电子设备中都广泛应用IIC总线有两条总线线路,一条是串行数据线(SDA),一条是串行时钟线(SCL)。
SDA负责数据传输,SCL负责数据传输的时钟同步。
IIC设备通过这两条总线连接到处理器的IIC总线控制器上。
一种典型的设备连接如图:与其他总线相比,IIC总线有很多重要的特点。
在选择一种设备来完成特定功能时,这些特点是选择IIC设备的重要依据。
主要特点:1,每一个连接到总线的设备都可以通过唯一的设备地址单独访问2,串行的8位双向数据传输,位速率在标准模式下可达到100kb/s;快速模式下可以达到400kb/s;告诉模式下可以达到3.4Mb/s3,总线长度最长7.6m左右4,片上滤波器可以增加抗干扰能力,保证数据的完成传输5,连接到一条IIC总线上的设备数量只受到最大电容400pF的限制6,它是一个多主机系统,在一条总线上可以同时有多个主机存在,通过冲突检测方式和延时等待防止数据不被破坏。
同一时间只能有一个主机占用总线IIC总线在传输数据的过程中有3种类型的信号:开始信号、结束信号、和应答信号>>开始信号(S): 当SCL为高电平时,SDA由高电平向低电平跳变,表示将要开始传输数据>>结束信号(P):当SCL为高电平时,SDA由低电平向高电平跳变,表示结束传输数据>>响应信号(ACK): 从机接收到8位数据后,在第9个周期,拉低SDA电平,表示已经收到数据。
这个信号称为应答信号开始信号和结束信号的波形如下图:主机:IIC总线中发送命令的设备,对于ARM处理器来说,主机就是IIC控制器从机:接受命令的设备主机向从机发送数据:主机通过数据线SDA向从机发送数据。
当总线空闲时,SDA和SCL信号都处于高电平。
主机向从机发送数据的过程:1,当主机检测到总线空闲时,主机发出开始信号2,主机发送8位数据。
这8位数据的前7位表示从机地址,第8位表示数据的传输方向。
这时,第8位为0,表示向从机发送数据3,被选中的从机发出响应信号ACK4,从机传输一系列的字节和响应位5,主机接受这些数据,并发出结束信号P,完成本次数据传输由上图可知,IIC控制器主要是由4个寄存器来完成所有的IIC操作的。
IICCON:控制是否发出ACK信号,是否开启IIC中断IICSTAT:IICADD:挂载到总线上的从机地址。
该寄存器的[7:1]表示从机地址。
IICADD寄存器在串行输出使能位IICSTAT[4]为0时,才可以写入;在任何时候可以读出IICDS:保存将要发送或者接收到的数据。
IICCDS在串行输出使能IICSTAT[4]为1时,才可以写入;在任何时间都可以读出因为IIC设备种类太多,如果每一个IIC设备写一个驱动程序,那么显得内核非常大。
不符合软件工程代码复用,所以对其层次话:这里简单的将IIC设备驱动分为设备层、总线层。
理解这两个层次的重点是理解4个数据结构,这4个数据结构是i2c_driver、i2c_client、i2c_algorithm、i2c_adapter。
i2c_driver、i2c_client属于设备层;i2c_algorithm、i2c_adapter属于总线型。
如下图:设备层关系到实际的IIC设备,如芯片AT24C08就是一个IIC设备。
总线层包括CPU中的IIC总线控制器和控制总线通信的方法。
值得注意的是:一个系统中可能有很多个总线层,也就是包含多个总线控制器;也可能有多个设备层,包含不同的IIC设备由IIC总线规范可知,IIC总线由两条物理线路组成,这两条物理线路是SDA和SCL。
只要连接到SDA和SCL总线上的设备都可以叫做IIC设备。
一个IIC设备由i2c_client数据结构进行描述:struct i2c_client{unsigned short flags; //标志位unsigned short addr;//设备的地址,低7位为芯片地址char name[I2C_NAME_SIZE];//设备的名称,最大为20个字节struct i2c_adapter *adapter;//依附的适配器i2c_adapter,适配器指明所属的总线struct i2c_driver *driver;//指向设备对应的驱动程序struct device dev;//设备结构体int irq;//设备申请的中断号struct list_head list;//连接到总线上的所有设备struct list_head detected;//已经被发现的设备链表struct completion released;//是否已经释放的完成量};设备结构体i2c_client中addr的低8位表示设备地址。
设备地址由读写位、器件类型和自定义地址组成,如下图:第7位是R/W位,0表示写,2表示读,所以I2C设备通常有两个地址,即读地址和写地址类型器件由中间4位组成,这是由半导体公司生产的时候就已经固化了。
自定义类型由低3位组成。
由用户自己设置,通常的做法如EEPROM这些器件是由外部I芯片的3个引脚所组合电平决定的(A0,A1,A2)。
A0,A1,A2 就是自定义的地址码。
自定义的地址码只能表示8个地址,所以同一IIC总线上同一型号的芯片最多只能挂载8个。
AT24C08的自定义地址码如图:A0,A1,A2接低电平,所以自定义地址码为0;如果在两个不同IIC总线上挂接了两块类型和地址相同的芯片,那么这两块芯片的地址相同。
这显然是地址冲突,解决的办法是为总线适配器指定一个ID号,那么新的芯片地址就由总线适配器的ID和设备地址组成除了地址之外,IIC设备还有一些重要的注意事项:1,i2c_client数据结构是描述IIC设备的“模板”,驱动程序的设备结构中应包含该结构2,adapter指向设备连接的总线适配器,系统可能有多个总线适配器。
内核中静态指针数组adapters记录所有已经注册的总线适配器设备3,driver是指向设备驱动程序,这个驱动程序是在系统检测到设备存在时赋值的IIC设备驱动i2c_driver:struct i2c_driver{int id; //驱动标识IDunsigned int class; //驱动的类型int (*attach_adapter)(struct i2c_adapter *); //当检测到适配器时调用的函数int (*detach_adapter)(struct i2c_adapter*); //卸载适配器时调用的函数int (*detach_client)(struct i2c_client *) __deprecated; //卸载设备时调用的函数//以下是一种新类型驱动需要的函数,这些函数支持IIC设备动态插入和拔出。
如果不想支持只实现上面3个。
要不实现上面3个。
要么实现下面5个。
不能同时定义int (*probe)(struct i2c_client *,const struct i2c_device_id *); //新类型设备探测函数int (*remove)(struct i2c_client *); //新类型设备的移除函数void (*shutdown)(struct i2c_client *); //关闭IIC设备int (*suspend)(struct i2c_client *,pm_messge_t mesg); //挂起IIC设备int (*resume)(struct i2c_client *); //恢复IIC设备int (*command)(struct i2c_client *client,unsigned int cmd,void *arg); //使用命令使设备完成特殊的功能。
类似ioctl()函数struct devcie_driver driver; //设备驱动结构体const struct i2c_device_id *id_table; //设备ID表int (*detect)(struct i2c_client *,int kind,struct i2c_board_info *); //自动探测设备的回调函数const struct i2c_client_address_data *address_data; //设备所在的地址范围struct list_head clients; //指向驱动支持的设备};结构体i2c_driver和i2c_client的关系较为简单,其中i2c_driver表示一个IIC设备驱动,i2c_client表示一个IIC设备。
关系如下图:IIC总线适配器就是一个IIC总线控制器,在物理上连接若干个IIC设备。
IIC总线适配器本质上是一个物理设备,其主要功能是完成IIC总线控制器相关的数据通信:struct i2c_adapter{struct module *owner; //模块计数unsigned int id; //alogorithm的类型,定义于i2c_id.h中unsigned int class; //允许探测的驱动类型const struct i2c_algorithm *algo; //指向适配器的驱动程序void *algo_data; //指向适配器的私有数据,根据不同的情况使用方法不同int (*client_register)(struct i2c_client *); //设备client注册时调用int (*client_unregister(struct i2c_client *); //设备client注销时调用u8 level;struct mutex bus_lock; //对总线进行操作时,将获得总线锁struct mutex clist_lock ; //链表操作的互斥锁int timeout; //超时int retries; //重试次数struct device dev; //指向适配器的设备结构体int nr ;struct list_head clients; //连接总线上的设备的链表char name[48]; //适配器名称struct completion dev_released; //用于同步的完成量};每一个适配器对应一个驱动程序,该驱动程序描述了适配器与设备之间的通信方法:struct i2c_algorithm{int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msg, int num); //传输函数指针,指向实现IIC 总线通信协议的函数,用来确定适配器支持那些传输类型int (*smbus_xfer)(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data); //smbus方式传输函数指针,指向实现SMBus总线通信协议的函数。