首页 > 编程知识 正文

单片机设计开发的常用工具,单片机常用的界面开发工具

时间:2023-05-04 21:00:37 阅读:272250 作者:3336

此前我们已经对单片机的基本功能有了一定的了解,接下来我们介绍一下几款常见的单片机外部设备。首先是常用的LCD显示屏模块,此处选用LCD1602(器件名LM016L)进行介绍。然后是AD转换的部分,这里选择并行的ADC0808和DAC0808进行介绍。最后介绍一个使用I2C通信协议的AT24C1024外置EEPROM模块。
以上几种模块都是比较常见的外设组件。在此仅对各个模块做一个简单的介绍,并给出一套简单的例程示范。详细的使用方法请参考相应器件的数据手册。

LCD显示屏

如图为LCD1602显示屏,驱动一个LCD1602显示屏需要一个并行数据口data,数据/指令信号RS,读/写信号RW,使能信号E。
LCD1602的基本动作如下: static void Wait(void) //忙检测函数,最高位是0允许执行,1等待{ unsigned char sta = 0; data = 0xff; rs = 0; // 选择发送命令模式 rw = 1; // 选择读取模式 do{ en = 1; sta = data; en = 0; //使能,用完就拉低,释放总线 }while(sta & 0x80);}void Write(unsigned char rsc,unsigned char cmd)//写指令/数据函数,rsc是0写入指令,1写入数据 {Wait();// 先等待LCD1602处于不忙状态en = 0; // 禁止LCDrs = rsc; // 选择发送模式rw = 0; // 选择写入模式data = cmd; // 写数据en = 1; // 使能LCDen = 0;// 禁止LCD}

具体使用流程如下:
首先,进行LCD1602初始化。

void Init(){ Write(0, 0x38); // 按照数据手册,发送38Hdelay5ms();// 延时5msWrite(0, 0x38); // 按照数据手册,发送38Hdelay5ms();// 延时5msWrite(0, 0x38); // 按照数据手册,发送38Hdelay5ms();// 延时5msWrite(0, 0x38);// 显示模式设置Write(0, 0x08);// 关闭显示Write(0, 0x01);// 清屏(同时清数据指针)Write(0, 0x06);// 读写后指针自动加1Write(0, 0x0c);// 开显示,不显示光标}

此部分主要是按照初始化时序输入指令进行初始化,以及模式设置,然后就可以进行字符串显示了。

void SetCursor(unsigned char x, unsigned char y)//设置坐标,LCD1602的坐标地址为第一行0x80-0x8f,第二行0xc0-0xcf{ Write(0, 0x80 + 0x40*y + x);}void ShowStr(unsigned char x, unsigned char y, unsigned char *pStr)//在指定坐标显示字符串{ SetCursor(x, y); //设置起点的坐标 while (*pStr != ''){ Write(1, *pStr++);//自增写数据 }}

带字库的LCD12864使用方法与之类同,基本硬件操作部分与上述代码可以复用。LCD12864多一个串/并控制口PSB。
LCD12864初始化、光标控制、写数据指令如下:

void Init(){psb = 1; Write(0, 0x34); // 扩充指令操作delay5ms();// 延时5msWrite(0, 0x30); // 基本指令操作delay5ms();// 延时5msWrite(0, 0x0c); // 开显示,不显示光标delay5ms();// 延时5msWrite(0, 0x01);// 清屏(同时清数据指针)}void SetCursor(unsigned char x, unsigned char y)//设置坐标,LCD12864的坐标地址为0x80 0x90 0x88 0x98{ Write(0, 0x80 + y>1?0x08:0x00 + y%2?0x10:0x00 + x);}void ShowStr(unsigned char x, unsigned char y, unsigned char *pStr)//在指定坐标显示字符串 英文字符占半位 汉字占整位 自增{ SetCursor(x, y); //设置起点的坐标 while (*pStr != ''){ Write(1, *pStr++);//自增写数据 }}

2.AD/DA转换

如图为ADC0808模数转换芯片,驱动一个ADC0808模数转换芯片需要一个并行数据口data,启动信号ST,不高于640KHz的时钟信号CLK,同时监听转换完成信号EOC。ADC0808芯片的使用流程为:在脉冲信号CLK的驱动下,给ST一个正脉冲信号,则AD转换开始,等到EOC信号转为正,则转换结束,OUT1-8口自高向低输出数据(注意OUT1为最高位)。返回值为0-255,对应ADC输入的参考电平VREF-和VREF+,实际电压值将0-255等比变换至所需的电压区间即可。比如此题中测量电压为0-5V,则对应电压值为测量值/255*5(V)=测量值/51(V)。

unsigned char getdata(){unsigned char data;st = 0;st = 1;st = 0;oe = 0;while(!eoc);P1 = 0xFF;oe = 1;data = P1;oe = 0;return data;}

将读取的数据通过P3端口送到DAC0808,经运算放大器处理后可以看见输出电压,因为输出电压范围为0-10V,故可看见输出电压约为输入电压值的两倍。

I2C+EEPROM

如图为AT24C1024外置存储设备的使用。AT24C1024是一个1024K大小的串行EEPROM,通过I2C协议进行读写,使用SCL、SDA端口。WP用于写保护开关,为1开启写保护,A1用于硬件地址选择,默认为0,可以与其他芯片连接。下面我将给出该设备的使用代码,并进行解释。
首先是I2C通信协议所需要的部分。I2C协议需要的函数有如下几个:void Start_I2c(); 总线启动函数,用于启动I2C通信void Stop_I2c(); 总线终止函数,用于结束I2C通信void sendByte(unsigned char c); 数据发送函数,发单个字符数据unsigned char RcvByte(); 数据接收函数,收单个字符数据void Ack_I2c(void); 应答子函数,表示数据成功接收void NoAck_I2c(void); 非应答子函数,通知设备结束发送
此外还需要一个全局接收标志符ack,作为应答标志。 //启动总线void Start_I2c(){ SDA=1;//发送起始条件的数据信号 _Nop(); SCL=1;//SCL保持高电平,总线开启 _Nop(); _Nop(); _Nop(); _Nop(); _Nop(); //5周期延时 SDA=0;//SDA负跳变,表示起始信号 _Nop(); _Nop(); _Nop(); _Nop(); _Nop(); //5周期延时 SCL=0; //暂停I2C总线,准备接收操作 _Nop(); _Nop(); //2周期延时}//结束总线void Stop_I2c(){ SDA=0;//发送结束条件的数据信号 _Nop(); SCL=1; //SCL保持高电平,总线开启 _Nop(); _Nop(); _Nop(); _Nop(); _Nop(); //5周期延时 SDA=1; //SDA正跳变,表示结束信号 _Nop(); _Nop(); _Nop(); _Nop(); //4周期延时,结束}//字节数据传送函数 void sendByte(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; //SCL保持高电平,总线开启 _Nop(); _Nop(); _Nop(); _Nop(); _Nop(); //5周期延时 SCL=0; //暂停I2C总线,准备接收操作 } _Nop(); _Nop();//2周期延时 SDA=1; //数据线置位,准备接收 _Nop(); _Nop();//2周期延时 SCL=1;//SCL保持高电平,总线开启 _Nop(); _Nop(); _Nop();//3周期延时 if(SDA==1) ack=0; //判断是否接收 else ack=1; SCL=0;//暂停I2C总线,准备接收操作 _Nop(); _Nop(); //2周期延时}//字节数据接收函数 unsigned char RcvByte(){ unsigned char retc; unsigned char BitCnt; retc=0; //数据接收临时变量 SDA=1; //数据线置位,准备接收 for(BitCnt=0;BitCnt<8;BitCnt++)//一个字符数据长度为8位 { _Nop(); SCL=0; //暂停I2C总线,准备接收操作 _Nop(); _Nop(); _Nop(); _Nop(); _Nop(); //5周期延时 SCL=1; //SCL保持高电平,总线开启 _Nop(); _Nop();//2周期延时 retc=retc<<1;//移位 if(SDA==1) retc=retc+1;//接收对应位数据 _Nop(); _Nop();//2周期延时} SCL=0;//暂停I2C总线,准备接收操作 _Nop(); _Nop();//2周期延时return retc;}//应答信号void Ack_I2c(void){ SDA=0;//发送结束条件的数据信号 _Nop(); _Nop(); _Nop();//3周期延时 SCL=1;//SCL保持高电平,总线开启 _Nop(); _Nop(); _Nop(); _Nop(); _Nop(); //5周期延时 SCL=0;//暂停I2C总线,准备接收操作 _Nop(); _Nop();//2周期延时 }//非应答信号void NoAck_I2c(void){ SDA=1;//数据线置位 _Nop(); _Nop(); _Nop();//3周期延时 SCL=1;//SCL保持高电平,总线开启 _Nop(); _Nop(); _Nop(); _Nop(); _Nop(); //5周期延时 SCL=0;//暂停I2C总线,准备接收操作 _Nop(); _Nop();//2周期延时 }

以上就是I2C总线通讯的基本操作函数,_Nop()为空指令函数,表示延时一个周期。使用时遵循启动-发送-结束或者启动-接收-应答函数-结束即可。
下面是AT24C1024使用I2C的处理函数。AT24C1024使用到的函数如下:

数据发送函数bit mcu_sendByte(
unsigned char add,
unsigned char dat);
参数add:地址,dat:数据;返回值:成功/失败。字符串发送函数bit mcu_send_string(
unsigned char add,
unsigned char rom_add_h,
unsigned char rom_add_l,
unsigned char *s,
unsigned char num);
参数add:地址,rom_add:rom高/低地址,s:字符串,num:字符位数;返回值:成功/失败。数据接收函数bit mcu_RcvByte(
unsigned char add,
unsigned char *c);
参数add:地址,c:接收数据地址;返回值:成功/失败。字符串接收函数bit mcu_receive_string(
unsigned char add,
unsigned char rom_add_h,
unsigned char rom_add_l,
unsigned char *s,
unsigned char num);
参数add:地址,rom_add:rom高/低地址,s:字符串,num:字符位数;返回值:成功/失败。 //器件当前地址写字节数据bit mcu_sendByte(unsigned char add, unsigned char dat){ Start_I2c();//I2C开始 sendByte(add);//写器件地址 if(ack==0)return 0; sendByte(dat); //如果应答,则发送数据 if(ack==0)return 0;Stop_I2c();//正常结束,返回1 return 1;}//向器件指定地址写字符串bit mcu_send_string(unsigned char add,unsigned char rom_add_h,unsigned char rom_add_l,unsigned char *s,unsigned char num){unsigned char i;Start_I2c();//I2C开始 sendByte(add);//写器件地址 if(ack==0) return 0; sendByte(rom_add_h);//如果应答,发地址高8位 if(ack==0) return 0; sendByte(rom_add_l);//如果应答,发地址低8位 if(ack==0) return 0; for(i=0;i<num;i++) //连续发num个数据 { sendByte(*s); if(ack==0) return 0; s++; } Stop_I2c();//正常结束,返回1 return 1;}//读器件当前地址数据bit mcu_RcvByte(unsigned char add,unsigned char *c){ Start_I2c();//I2C开始 sendByte(add);//写器件地址 if(ack==0)return 0; *c=RcvByte(); //如果应答,则读取数据 NoAck_I2c(); //送非应答信号 Stop_I2c();//正常结束,返回1 return 1;}//从器件指定地址读字符串bit mcu_receive_string(unsigned char add,unsigned char rom_add_h,unsigned char rom_add_l,unsigned char *s,unsigned char num){ unsigned char i; Start_I2c();//I2C开始 sendByte(add);//写器件地址 if(ack==0) return 0; sendByte(rom_add_h);//如果应答,发地址高8位 if(ack==0) return 0; sendByte(rom_add_l);//如果应答,发地址低8位 if(ack==0) return 0; Start_I2c();//I2C重新开始 sendByte(add+1);//写器件地址,方式为读 if(ack==0) return 0; for(i=0;i<num;i++)//连续读num次数据 { *s=RcvByte();//读取数据 Ack_I2c(); //送应答信号 s++;//地址自增 } *s=RcvByte();//读取数据 NoAck_I2c();//送非应答信号 Stop_I2c();//正常结束,返回1 return 1;}

在如图的示例程序中,我们从0x0000开始向EEPROM写入10位数据"1234567890",然后依次从0x0000-0x0010之间读取10位数据,可以看到每次接收的数据前移一位。关闭单片机并重新启动,数据依然可以正常读取。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。