#include <pic.h> //此程序实现"数控步进直流稳压电源"的功能,调试时为了避免资源冲突,应使实验板上的拔码开关S8拔向高电平 //本程序设定S9键为增加键,当按住S9键不松开时,输出Vout以0.1V连续步进, //直至键S9松开,当以一定的时间间隔点动S9键时,输出Vout也为点动步进 //递减键S11的功能与S9基本相同时,输出电压的值显示在3个LED上 unsigned char R1,R2,R3,TXDATA,LEDF,BJF,COUNTW,data; unsigned int i; const char table[11]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0XD8,0x80,0x90,0xFF}; //不带小数点的显示段码表 const char table0[11]={0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10,0xFF}; //带小数点的的显示段码表 unsigned char s[4]; //定义一个显示缓冲数组 //把需要显示的数字装入显示缓冲数组 void sfz() { s[0]=R3; s[1]=R2; s[2]=R1; s[3]=0x0A; //最后一个LED显示"DARK" } //系统各寄存器初始化子程序 void initial() { R1=0X00; R2=0X00; R3=0X00; sfz(); //把需要显示的数字装入显示缓冲数组 TXDATA=0X00; LEDF=0X01; BJF=0X01; TRISB1=0; TRISB2=0; TRISB4=1; TRISB5=1; //设置与键盘相关的各口的输入输出方式 RB1=0; RB2=0; //设置扫描初始条件 } //spi方式显示初始化子程序 void SPIINIT() { PIR1=0; SSPCON=0x30; SSPSTAT=0xC0; //设置SPI的控制方式,允许SSP方式,并且时钟下降沿发送,与"74HC595,当其 //SCLK从低到高跳变时,串行输入寄存器"的特点相对应 TRISC=0xD7; //SDO引脚为输出,SCK引脚为输出 TRISA5=0; //RA5引脚设置为输出,以输出显示锁存信号 } //I2C初始化子程序 void i2cint() { SSPCON = 0X08; //初始化SSPCON寄存器 TRISC3 =1; //设置SCL为输入口 TRISC4 =1; //设置SDA为输入口 TRISA4 = 0; SSPSTAT=0X80; //初始化SSPSTAT寄存器 SSPADD=0X02; //设定I2C时钟频率 SSPCON2=0X00; //初始化SSPCON2寄存器 di(); //关闭总中断 SSPIF=0; //清SSP中断标志 RA4=0; //关掉74HC165的移位时钟使能,以免74HC165 //移位数据输出与I2C总线的数据线发生冲突 SSPEN=1; //SSP模块使能 } //软件延时子程序 void DELAY() { for(i = 3553; --i ;) continue; } //键服务子程序 void keyserve() { PORTB=0XFD ; if(RB5==0) BJF=0X01; //S9键按下,步进加标志置1 PORTB=0XFB ; if(RB5==0) BJF=0X00; //S11键按下,步进加标志清0 RB1=0; //恢复PORTB的值 RB2=0; } //键扫描子程序 void KEYSCAN() { while(1){ while(1) { if (RB5==0) break; } DELAY(); //若有键按下,则软件延时 if (RB5==0) break; //若还有键按下,则终止循环扫描,返回 } } //SPI传送数据子程序 void SPILED(data) { SSPBUF=data; // 启动发送 do { ; }while(SSPIF==0); SSPIF=0; } //显示子程序 void display() { SPIINIT(); //spi方式显示初始化 RA5=0; //准备锁存 for(COUNTW=0;COUNTW<4;COUNTW++) { data=s[COUNTW]; if(COUNTW==1) data=table0[data];//第二位需要显示小数点 else data=table[data]; SPILED(data); //发送显示段码 } for(COUNTW=0;COUNTW<4;COUNTW++){ data=0xFF; SPILED(data); //连续发送4个DARK,使显示看起来好看一些 } RA5=1; //最后给一个锁存信号,代表显示任务完成 } //I2C总线输出数据子程序 void i2cout() { i2cint(); //因为SPI输出和I2C输出不能同时工作,则需要 //不断在两种方式见切换 SEN=1; //产生I2C启动信号 for(i=0x02;--i;) continue; //给予一定的延时,保证启动 do { RSEN=1; //产生I2C启动信号 }while(SSPIF==0); //如果没能启动,则反复启动,直到启动为止 SSPIF=0; //SSPIF标志清0 SSPBUF=0X58; //I2C总线发送地址字节 do { ; }while(SSPIF==0); //等待地址发送完毕 SSPIF=0; //SSPIF标志清0 SSPBUF=0X01; //I2C总线发送命令字节 do { ; }while(SSPIF==0); //等待命令发送完毕 SSPIF=0; //SSPIF标志清0 SSPBUF=TXDATA; //I2C总线发送数据字节 do { ; }while(SSPIF==0); //等待数据发送完毕 SSPIF=0; //SSPIF标志清0 PEN=1; //产生停止条件 do { ; }while(SSPIF==0); //等待停止条件产生 SSPIF=0; //SSPIF标志清0 } //步进加子程序 void BJADD() { R1++; TXDATA=TXDATA+2; if(R1>9) { R1=0; R2++; if(R2>9) { R2=0; R3++; } } if((R3==1)&&(R2==2)&&(R1==1)){ R3=0; R2=0; R1=0; //若R3,R2,R1超过120,则又从0计起 TXDATA=0; } sfz(); //把需要显示的数字装入显示缓冲数组 } //步进减子程序 void BJSUB() { R1--; TXDATA=TXDATA-2; if(R1==0XFF) { R1=9; R2--; if(R2==0XFF) { R2=9; R3--; if(R3==0XFF) { R3=1; R2=2; R1=0; //若R3,R2,R1小于0,则又从120计起 TXDATA=0XF0; } } } sfz(); //把需要显示的数字装入显示缓冲数组 } //主程序 main() { initial(); //系统各寄存器初始化 display(); //调用一次显示子程序 while(1) { i2cout(); //调用I2C子程序,启动D/A转换 KEYSCAN(); //键盘扫描 keyserve() ; //若确实有键按下,则调用键服务程序 if(BJF==0X01) BJADD();//若步进加标志为1,则调用步进加子程序 else BJSUB(); //若步进加标志为0,则调用步进减子程序 display(); //调用一次显示子程序 } }
|