基于51单片机的灯盘检测(PCF8591+CD4051 )
基于51单片机的灯盘检测系统使用,AT89C51作为系统主控,采用PCF8591+CD4051进行循环检测,本次的led灯一共有90个并在每个led上做了一个断路模拟开关,部分led上还设置了击穿模拟开关,led点亮使用PNP三极管进行导通,低电平的导通方式。
一、参考代码
1、扫描灯盘
本次设计使用PCF8591和CD4051配合进行90个led的扫描,首先使用传入的变量进行通道选择DA、DB、DC分别使用的引脚是P22、P23、P24进行CD4051通道的选择,ADC读取采取统一通道,即AN0通道。接着再使用成对的CD4051进行扫描,以此类推最后进行了90个led的扫描。
void ScanLed(unsigned char n)
{//选择灯盘 1110 0011P2 &= 0xE3;//选择灯盘P2 |= (n << 2); //清除低四位P1 &= 0xF0;j=0;while(j<16){if(led_state == n+1){P1 &= 0xf0;//选择通道P1 |= j;//获取ADC的值Invalue = read_AD_data(0x40);if(Invalue==0 || Invalue>=250){if(n==0){err1_led[num1] = n*16+j-1;num1++;}if(n==1){err2_led[num2] = n*16+j-1;num2++;}if(n==2){err3_led[num3] = n*16+j-1;num3++;}if(n==3){err4_led[num4] = n*16+j-1;num4++;}if(n==4){err5_led[num5] = n*16+j-1;num5++;}} }j++; }
}
2、主函数
下面是本次设计的主函数,实现了灯盘控制,检测灯一些逻辑,利用串口中断进行灯盘异常数据的获取并控制led灯。
#include <REGX52.H>
#include "LCD1602.H"
#include "delay.h"
#include "PCF8591.h"
#include "UART.h"sbit led1 = P3^3;
sbit led2 = P3^4;
sbit led3 = P3^5;
sbit led4 = P3^6;
sbit led5 = P3^7;//轮询芯片的IO口
sbit DA = P2^2;
sbit DB = P2^3;
sbit DC = P2^4;sbit DA0 = P1^0;
sbit DB0 = P1^1;
sbit DC0 = P1^2;
sbit DD0 = P1^3;typedef unsigned char u8;u8 Invalue=100;
u8 i=0,j=0;u8 num1=0;
u8 num2=0;
u8 num3=0;
u8 num4=0;
u8 num5=0;u8 err1_led[10] = {0};
u8 err2_led[10] = {0};
u8 err3_led[10] = {0};
u8 err4_led[10] = {0};
u8 err5_led[10] = {0};u8 pos=0;
u8 close=0;u8 cmd=0;
u8 led_state=0;void ScanLed(unsigned char n)
{//选择灯盘 1110 0011P2 &= 0xE3;//选择灯盘P2 |= (n << 2); //清除低四位P1 &= 0xF0;j=0;while(j<16){if(led_state == n+1){P1 &= 0xf0;//选择通道P1 |= j;//获取ADC的值Invalue = read_AD_data(0x40);if(Invalue==0 || Invalue>=250){if(n==0){err1_led[num1] = n*16+j-1;num1++;}if(n==1){err2_led[num2] = n*16+j-1;num2++;}if(n==2){err3_led[num3] = n*16+j-1;num3++;}if(n==3){err4_led[num4] = n*16+j-1;num4++;}if(n==4){err5_led[num5] = n*16+j-1;num5++;}} }j++; }
}void main()
{LCD_Init();UART_Init();//led灯开启led1=1;led2=1;led3=1;led4=1;led5=1;while(1){ Invalue = read_AD_data(0x40);//清空坏灯的数组for(i=0; i<5; i++){err1_led[i] = 0;err2_led[i] = 0;err3_led[i] = 0;err4_led[i] = 0;err5_led[i] = 0;}num1 = 0;if(led_state == 1){ ScanLed(0);}num2 = 0;if(led_state == 2){ScanLed(1); }num3 = 0;if(led_state == 3){ScanLed(2); }num4 = 0;if(led_state == 4){ScanLed(3); }num5 = 0;if(led_state == 5){ScanLed(4); }//红灯故障超过了4个,红灯灭掉if(num1 >= 5){led_state=6;led1=1;}else{}//其它四个灯盘,灭了超过4个,点亮红灯if(num2 >= 5 || num3 >= 5 || num4 >= 5 || num5 >= 5 ){led_state=1;led1=0;led2=1;led3=1;led4=1;led5=1; }LCD_ShowNum(2, 1, num1+num2+num3+num4+num5, 2); if(num1 != 0 || num2 != 0 || num3 != 0 || num4 != 0 || num5 != 0){ //发送数据包过去UART_SendByte(0x5A);//显示坏灯的数据if(num1 != 0){//显示灯坏的数量 for(i=0; i<num1; i++){UART_SendByte(err1_led[i]);} } if(num2 != 0){//显示灯坏的数量 for(i=0; i<num2; i++){UART_SendByte(err2_led[i]);} } if(num3 != 0){//显示灯坏的数量 for(i=0; i<num3; i++){UART_SendByte(err3_led[i]);} } if(num4 != 0){//显示灯坏的数量 for(i=0; i<num4; i++){UART_SendByte(err4_led[i]);} } if(num5 != 0){//显示灯坏的数量 for(i=0; i<num5; i++){UART_SendByte(err5_led[i]);} } UART_SendByte(0xA5); }}
} void UATR_Routine() interrupt 4
{if(RI==1){cmd = SBUF;if(cmd=='a'){led_state=1;}if(cmd=='b'){led_state=2;}if(cmd=='c'){led_state=3;}if(cmd=='d'){led_state=4;}if(cmd=='e'){led_state=5;}if(cmd=='f'){led_state=6;}if(led_state==1){led1=0;led2=1;led3=1;led4=1;led5=1;} if(led_state==2){led1=1;led2=0;led3=1;led4=1;led5=1; }if(led_state==3){led1=1;led2=1;led3=0;led4=1;led5=1; }if(led_state==4){led1=1;led2=1;led3=1;led4=0;led5=1; }if(led_state==5){led1=1;led2=1;led3=1;led4=1;led5=0; }if(led_state==6){led1=1;led2=1;led3=1;led4=1;led5=1; }RI=0;}
}
二、功能演示
1、串口控制亮灯
串口分别发送a、b、c、d、e、f,分别是点亮这5个led灯盘和关闭所有灯盘,如图,发送指令a可以点亮第一个灯盘。如下,当我发送a的时候灯盘1灯被点亮。
2、故障检测
如下图,利用串口助手发送c指令,第三个灯盘被点亮,同时串口循环打印检测到的故障灯,数据格式是0x5A+数据+0xA5这样的格式,如下图数据大致是 22、20、2d(0为开始数),表示第三个灯盘的第3个灯、第三个灯盘的第10个灯、第三个灯盘的第13个灯,同时lcd显示故障灯数量,这里是3个。
三、项目总结
本次项目使用51单片机加PCF8591加CD4051实现了串口无线灯盘控制及检测,同时串口可以定位到具体得到故障灯盘,LCD显示灯盘故障数量。