Giải pháp cho Giải quốc gia vi điều khiển Lantiao Cup lần thứ 13

Chuẩn bị

1. Mã nguồn các mô-đun nền

Init.c


#include <Init.h>

void SystemInit()
{
	P0 = 0xff;
	P2 = P2 & 0x1f | 0x80;
	P2 &= 0x1f;
	
	P0 = 0x00;
	P2 = P2 & 0x1f | 0xa0;
	P2 &= 0x1f;
}

key.c


#include <key.h>

unsigned char DocNhan(void)
{
	unsigned char temp = 0;
	
	if(P33 == 0) temp = 4;
	if(P32 == 0) temp = 5;
	if(P31 == 0) temp = 6;
	if(P30 == 0) temp = 7;
	
	return temp;
}

seg.c


#include <seg.h>

code unsigned char Seg_Table[] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0xff, //trống
0x8e, //F
0x89, //H
0x88, //A
0x8c  //P
};

void HienThiSeg(unsigned char wela, unsigned char dula, unsigned char point)
{
	P0 = 0xff;
	P2 = P2 & 0x1f | 0xe0;
	P2 &= 0x1f;
	
	P0 = (0x01 << wela);
	P2 = P2 & 0x1f | 0xc0;
	P2 &= 0x1f;
	
	P0 = Seg_Table[dula];
	if(point)
		P0 &= 0x7f;
	P2 = P2 & 0x1f | 0xe0;
	P2 &= 0x1f;
}

wave.c


#include <wave.h>

sbit Tx = P1^0;
sbit Rx = P1^1;

void Delay12us(void)	//@12.000MHz
{
	unsigned char data i;

	_nop_();
	_nop_();
	i = 35;
	while (--i);
}


void KhoiDongSong()
{
	unsigned char i;
	EA = 0;
	for(i = 0; i < 8; i++)
	{
		Tx = 1;
		Delay12us();
		Tx = 0;
		Delay12us();
	}
	EA = 1;
}

unsigned char DocSong()
{
	unsigned int time;
	CMOD = 0x00;
	CH = CL = 0;
	KhoiDongSong();
	CR = 1;
	while(Rx && !CF);
	CR = 0;
	if(CF)//dữ liệu tràn
	{
		CF = 0;
		return 0;
	}
	else
	{
		time = (CH << 8) | CL;
		return time * 0.017;
	}
}

led.c


#include <led.h>

void HienThiLed(unsigned char *ucLed)
{
	unsigned char i, temp = 0x00;
	static unsigned char temp_old = 0xff;
	
	for(i = 0; i < 8; i++)
		temp |= (ucLed[i] << i);
	
	if(temp != temp_old)
	{
		P0 = ~temp;
		P2 = P2 &  0x1f | 0x80;
		P2 &= 0x1f;
		temp_old = temp;
	}
}

unsigned char temp1 = 0x00;
static unsigned char temp1_old = 0xff;

//1-đèn sáng
void Rơle(bit enable)
{
	if(enable)
		temp1 |= 0x10;
	else
		temp1 &= ~0x10;
	
	if(temp1 != temp1_old)
	{
		P0 = temp1;
		P2 = P2 &  0x1f | 0xa0;
		P2 &= 0x1f;
		temp1_old = temp1;
	}
}

void MayQuay(bit enable)
{
	if(enable)
		temp1 |= 0x20;
	else
		temp1 &= ~0x20;
	
	if(temp1 != temp1_old)
	{
		P0 = temp1;
		P2 = P2 &  0x1f | 0xa0;
		P2 &= 0x1f;
		temp1_old = temp1;
	}
}

2. main.c

Nếu bạn sử dụng mẫu dưới đây, bạn có thể đặt việc đọc AD, DA, EEPROM và cảm biến siêu âm cùng vào hàm `XuLySeg`, điều này có thể hoạt động tốt cho các bài thi cấp tỉnh. Tuy nhiên, với bài thi này, cách làm này sẽ khiến hàm xử lý dữ liệu cho mạch 7-segment quá tải, dẫn đến một số dữ liệu chưa được xử lý xong đã thoát. Nếu bạn sử dụng bộ lập lịch, bạn nên phân bổ thời gian cho các phần như sau: `XuLyNhan` 10ms, `XuLySeg` 100ms, `XuLySong` 160ms, `XuLyIIC`: 160ms, `XuLyLed`: 1ms.


#include <Init.h>
#include <led.h>
#include <key.h>
#include <seg.h>
#include <wave.h>
#include <iic.h>

typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long int u32;
/*độ trễ*/
idata u8 delayKey;              //độ trễ nút bấm 10ms
idata u8 delaySeg;			   //độ trễ mạch 7-segment 200ms
/*nút bấm*/
idata u8 giaTriNhan, nhanXuong, nhanLen, nhanCu;
idata bit flagNhanDai;        //cờ nhấn giữ
idata u16 dem_1000ms;         //giữ 1s
/*mạch 7-segment*/
idata u8 viTriSeg;
pdata u8 bufSeg[8] = {10,10,10,10,10,10,10,10};
pdata u8 dauChamSeg[8] = {0,0,0,0,0,0,0,0};
idata u8 cheDoSeg;        	   //trang chủ 0-tần số 1-độ ẩm 2-khoảng cách 3-tham số
idata u8 cheDoCaiDat;        	   //trang tham số 0-tần số 1-độ ẩm 2-khoảng cách
idata bit flagKhoangCach; 	   //cờ chế độ khoảng cách 0-cm 1-m
idata bit flagTanSo;     	   //cờ chế độ tần số 0-hz 1-khz
/*tần số*/
idata u16 tanSo, dem_1s; 	   //tần số
idata float tanSo_khz;
idata float tanSoCaiDat = 9; 	   //tham số tần số, giá trị ban đầu 9khz, phạm vi 1.0~12.0
idata bit flagTanSo;           //cờ tần số lớn hơn tham số
/*độ ẩm*/
idata u8 doAm;      	   //độ ẩm
idata u8 doAmCaiDat = 40;	   //tham số độ ẩm, giá trị ban đầu 40, phạm vi 10~60
idata bit flagDoAm;       //cờ độ ẩm lớn hơn tham số
/*cảm biến siêu âm*/
idata u8 khoangCachCm;     	   //đo khoảng cách cm
idata u8 khoangCachM_10x = 6;   //tham số siêu âm, giá trị ban đầu 0.6m, phạm vi 0.1~1.2m
idata bit flagKhoangCach;       //cờ khoảng cách lớn hơn tham số
/*đèn chỉ thị*/
pdata u8 led[8] = {0,0,0,0,0,0,0,0};
idata bit flagDenBat;            //cờ nhấp nháy đèn
idata u8 dem_100ms;           //nhấp nháy 1 lần/100ms
idata u8 demRơle;           //số lần bật tắt rơ-le
idata u8 mucPWM;            //tỷ lệ duty cycle PWM
idata u8 demPWM;			   //đếm thời gian PWM

void XuLyNhan()
{
	delayKey = 1;
	giaTriNhan = DocNhan();
	nhanXuong = giaTriNhan & ~nhanCu;
	nhanLen = ~giaTriNhan & nhanCu;
	nhanCu = giaTriNhan;
	switch(nhanXuong)
	{
	}
}

void XuLySeg()
{
	if(delaySeg)
		return;
	delaySeg= 1;
	/*AD*/
	float RB2 = DocAD() / 51.0;
	/*cảm biến siêu âm*/
	khoangCachCm = DocSong() + 2;
	switch(cheDoSeg)
	{	
		case 0://trang tần số
		break;
			
		case 1://trang độ ẩm
		break;
		
		case 2://trang khoảng cách
		break;
			
		case 3://trang tham số
			switch(cheDoCaiDat)
			{
				case 0://tham số tần số
				break;
				
				case 1://tham số độ ẩm
				break;
				
				case 2://tham số khoảng cách
				break;
			}
		break;
	}
}

void XuLyLed()
{
	
}

void KhoiDongTimer0(void)		//0 micro giây @12.000MHz
{
	TMOD &= 0xF0;			//cài đặt chế độ timer
	TMOD |= 0x05;			//cài đặt chế độ timer
	TL0 = 0;				//giá trị khởi tạo
	TH0 = 0;				//giá trị khởi tạo
	TF0 = 0;				//xóa cờ TF0
	TR0 = 1;				//bắt đầu timer 0
}

void KhoiDongTimer1(void)		//1 mili giây @12.000MHz
{
	AUXR &= 0xBF;			//chế độ đồng hồ timer 12T
	TMOD &= 0x0F;			//cài đặt chế độ timer
	TL1 = 0x18;				//giá trị khởi tạo
	TH1 = 0xFC;				//giá trị khởi tạo
	TF1 = 0;				//xóa cờ TF1
	TR1 = 1;				//bắt đầu timer 1
	ET1 = 1;				//kích hoạt ngắt timer 1
	EA = 1;
}

void KhoiDongTimer2(void)		//100 micro giây @12.000MHz
{
	AUXR &= 0xFB;			//chế độ đồng hồ timer 12T
	T2L = 0x9C;				//giá trị khởi tạo
	T2H = 0xFF;				//giá trị khởi tạo
	AUXR |= 0x10;			//bắt đầu timer 2
	IE2 |= 0x04;			//kích hoạt ngắt timer 2
}

void NgatTimer1(void) interrupt 3
{
	if(++delayKey == 10) delayKey = 0; //độ trễ nút bấm 10ms
	if(++delaySeg == 200) delaySeg = 0;//độ trễ mạch 7-segment 100ms
	if(++viTriSeg == 8)
		viTriSeg = 0;
	HienThiSeg(viTriSeg, bufSeg[viTriSeg], dauChamSeg[viTriSeg]);
	//NE555
	if(++dem_1s == 1000)
	{
		dem_1s = 0;
		tanSo = (TH0 << 8) | TL0;
		TH0 = TL0 = 0;
	}
	/*rơ-le*/
	Rơle(flagKhoangCach);
	/*Led*/
	HienThiLed(led);
}

void NgatTimer2(void) interrupt 12
{
	
}

void main()
{
	SystemInit();
	KhoiDongTimer0();
	KhoiDongTimer1();
	KhoiDongTimer2();
	while(1)
	{
		XuLyNhan();
		XuLySeg();
		XuLyLed();
	}
}

Mạch hiển thị 7-segment


/*mạch 7-segment*/
idata u8 viTriSeg;
pdata u8 bufSeg[8] = {10,10,10,10,10,10,10,10};
pdata u8 dauChamSeg[8] = {0,0,0,0,0,0,0,0};
idata u8 cheDoSeg;        	   //trang chủ 0-tần số 1-độ ẩm 2-khoảng cách 3-tham số
idata u8 cheDoCaiDat;        	   //trang tham số 0-tần số 1-độ ẩm 2-khoảng cách
idata bit flagKhoangCach; 	   //cờ chế độ khoảng cách 0-cm 1-m
idata bit flagTanSo;     	   //cờ chế độ tần số 0-hz 1-khz
/*tần số*/
idata u16 tanSo, dem_1s; 	   //tần số
idata float tanSo_khz;
idata float tanSoCaiDat = 9; 	   //tham số tần số, giá trị ban đầu 9khz, phạm vi 1.0~12.0
/*độ ẩm*/
idata u8 doAm;      	   //độ ẩm
idata u8 doAmCaiDat = 40;	   //tham số độ ẩm, giá trị ban đầu 40, phạm vi 10~60
/*cảm biến siêu âm*/
idata u8 khoangCachCm;     	   //đo khoảng cách cm
idata u8 khoangCachM_10x = 6;   //tham số siêu âm, giá trị ban đầu 0.6m, phạm vi 0.1~1.2m

void XuLySong()
{
	khoangCachCm = DocSong() + 2;
}

void XuLyIIC()
{
	/*AD*/
	float RB2 = DocAD() / 51.0;
	//chuyển đổi điện áp sang độ ẩm
	if(RB2 >= 5.0)
		doAm = 100;
	else
		doAm = 20 * RB2;
}

void XuLySeg()
{
	switch(cheDoSeg)
	{	
		case 0://trang tần số
			bufSeg[0] = 11;//F
			bufSeg[1] = 10;
			bufSeg[2] = 10;
			dauChamSeg[6] = flagTanSo;//chuyển đổi chế độ cm/m
			if(!flagTanSo)//chế độ cm
			{
					bufSeg[3] = (tanSo/10000%10)?tanSo/10000%10:10;
					bufSeg[4] = (tanSo/1000%10==0&&bufSeg[3]==10)?10:tanSo/1000%10;
					bufSeg[5] = (tanSo/100%10==0&&bufSeg[4]==10)?10:tanSo/100%10;
					bufSeg[6] = (tanSo/10%10==0&&bufSeg[5]==10)?10:tanSo/10%10;
					bufSeg[7] = tanSo%10;
			}
			else//chế độ m
			{
				bufSeg[3] = 10;
				bufSeg[4] = 10;
				bufSeg[5] = (u8)tanSo_khz / 10 % 10;
				if(!bufSeg[5]) bufSeg[5] = 10;
				bufSeg[6] = (u8)tanSo_khz % 10;
				bufSeg[7] = (u8)(tanSo_khz * 10) % 10;
			}
		break;
			
		case 1://trang độ ẩm
			bufSeg[0] = 12;//H
			bufSeg[3] = 10;
			bufSeg[4] = 10;
			bufSeg[5] = 10;
			bufSeg[6] = doAm / 10;
			bufSeg[7] = doAm % 10;
			dauChamSeg[6] = 0;
		break;
		
		case 2://trang khoảng cách
			bufSeg[0] = 13;//A
			if(!flagKhoangCach)//cm
			{
				if(khoangCachCm < 10)
				{
					bufSeg[5] = 10;
					bufSeg[6] = 10;
					bufSeg[7] = khoangCachCm % 10;
				}
				else
				{
					bufSeg[5] = khoangCachCm / 100 ? khoangCachCm / 100 : 10;
					bufSeg[6] = khoangCachCm / 10 % 10;
					bufSeg[7] = khoangCachCm % 10;
				}
				dauChamSeg[5] = 0;
			}
			else//m
			{
				bufSeg[5] = khoangCachCm / 100;
				bufSeg[6] = khoangCachCm / 10 % 10;
				bufSeg[7] = khoangCachCm % 10;
				dauChamSeg[5] = 1;
			}
		break;
			
		case 3://trang tham số
			bufSeg[0] = 14;//P
			bufSeg[1] = cheDoCaiDat + 1;
			bufSeg[2] = 10;
			bufSeg[3] = 10;
			bufSeg[4] = 10;
			switch(cheDoCaiDat)
			{
				case 0://tham số tần số
					bufSeg[5] = (u8)tanSoCaiDat / 10 ? tanSoCaiDat / 10 : 10;
					bufSeg[6] = (u8)tanSoCaiDat % 10;
					bufSeg[7] = (u8)(tanSoCaiDat * 10) % 10;
					dauChamSeg[6] = 1;
				break;
				
				case 1://tham số độ ẩm
					bufSeg[5] = 10;
					bufSeg[6] = doAmCaiDat / 10;
					bufSeg[7] = doAmCaiDat % 10;
					dauChamSeg[6] = 0;
				break;
				
				case 2://tham số khoảng cách
					bufSeg[6] = khoangCachM_10x / 10;
					bufSeg[7] = khoangCachM_10x % 10;
					dauChamSeg[6] = 1;
				break;
			}
		break;
	}
}

void NgatTimer1(void) interrupt 3
{
	systick++;
	if(++viTriSeg == 8)
		viTriSeg = 0;
	HienThiSeg(viTriSeg, bufSeg[viTriSeg], dauChamSeg[viTriSeg]);
	//NE555
	if(++dem_1s == 1000)
	{
		dem_1s = 0;
		tanSo = (TH0 << 8) | TL0;
		tanSo_khz = tanSo / 1000.0;
		TH0 = TL0 = 0;
	}
}

Xử lý nút bấm

1. S4, S5


void XuLyNhan()
{
	giaTriNhan = DocNhan();
	nhanXuong = giaTriNhan & ~nhanCu;
	nhanLen = ~giaTriNhan & nhanCu;
	nhanCu = giaTriNhan;
	
	switch(nhanXuong)
	{
		case 4:
			if(++cheDoSeg == 4)
				cheDoSeg = 0;
			if(cheDoSeg == 0)
				cheDoCaiDat = 0;
		break;
			
		case 5:
			if(cheDoSeg == 3)
				if(++cheDoCaiDat == 3)
					cheDoCaiDat = 0;
		break;
	}
}

2. S6


void XuLyNhan()
{
	giaTriNhan = DocNhan();
	nhanXuong = giaTriNhan & ~nhanCu;
	nhanLen = ~giaTriNhan & nhanCu;
	nhanCu = giaTriNhan;

	switch(nhanXuong)
	{
		case 6:
			if(cheDoSeg == 2)
				flagKhoangCach = !flagKhoangCach;
			else if(cheDoSeg == 3)//+
			{
				if(!cheDoCaiDat)//tham số tần số tăng 0.5 mỗi lần
				{
					tanSoCaiDat += 0.5;
					if(tanSoCaiDat == 12.5)
						tanSoCaiDat = 1.0;
				}
				else if(cheDoCaiDat == 1)//tham số độ ẩm tăng 10 mỗi lần
				{
					doAmCaiDat += 10;
					if(doAmCaiDat == 70)
						doAmCaiDat = 10;
				}
				else//tham số khoảng cách tăng 0.1 mỗi lần (tăng 1)
				{
					if(++khoangCachM_10x == 13)
						khoangCachM_10x = 1;
				}
			}
		break;
	}
}	

3. S7


void XuLyNhan()
{
	giaTriNhan = DocNhan();
	nhanXuong = giaTriNhan & ~nhanCu;
	nhanLen = ~giaTriNhan & nhanCu;
	nhanCu = giaTriNhan;
	
	if(cheDoSeg == 1)//trên trang độ ẩm, nhấn giữ để xóa số lần rơ-le
	{
		if(nhanXuong == 7)
			flagNhanDai = 1;
		if(nhanLen == 7)
		{
			flagNhanDai = 0;
			if(dem_1000ms >= 1000)
			{
				demRơle = 0;
			}
		}
	}

	switch(nhanXuong)
	{
		case 7:
			if(!cheDoSeg)
				flagTanSo = !flagTanSo;
			else if(cheDoSeg == 3)//-
			{
				if(!cheDoCaiDat)//tham số tần số giảm 0.5 mỗi lần
				{
					tanSoCaiDat -= 0.5;
					if(tanSoCaiDat == 0.5)
						tanSoCaiDat = 12.0;
				}
				else if(cheDoCaiDat == 1)//tham số độ ẩm giảm 10 mỗi lần
				{
					doAmCaiDat -= 10;
					if(doAmCaiDat == 0)
						doAmCaiDat = 60;
				}
				else//tham số khoảng cách giảm 0.1 mỗi lần (giảm 1)
				{
					if(--khoangCachM_10x == 0)
						khoangCachM_10x = 12;
				}
			}
		break;
	}
}
void NgatTimer1(void) interrupt 3
{
	//đếm thời gian nhấn giữ nút
	if(flagNhanDai)
	{
		if(++dem_1000ms >= 1000)
			dem_1000ms = 1000;
	}
	else
		dem_1000ms = 0;
}

Đèn chỉ thị


/*tần số*/
idata bit flagTanSo;           //cờ tần số lớn hơn tham số
/*độ ẩm*/
idata bit flagDoAm;       //cờ độ ẩm lớn hơn tham số
/*cảm biến siêu âm*/
idata bit flagKhoangCach;       //cờ khoảng cách lớn hơn tham số
void XuLySong()
{
	khoangCachCm = DocSong() + 2;
	flagKhoangCach = (khoangCachCm > khoangCachM_10x*10);
}

void XuLyIIC()
{
	//...
	flagDoAm = (doAm > doAmCaiDat);
}

void XuLyLed()
{
	u8 i;
	/*Led*/
	if(cheDoSeg != 3)
	{
		for(i = 0; i < 3; i++)
			led[i] = (i == cheDoSeg);
	}
	else
	{
		for(i = 0; i < 3; i++)
			led[i] = (i == cheDoCaiDat && flagDenBat);
	}
	led[3] = flagTanSo;
	led[4] = flagDoAm;
	led[5] = flagKhoangCach;
	HienThiLed(led);
}

void NgatTimer1(void) interrupt 3
{
	if(++dem_1s == 1000)
	{
		dem_1s = 0;
		tanSo = (TH0 << 8) | TL0;
		tanSo_khz = tanSo / 1000.0;
		TH0 = TL0 = 0;
		flagTanSo = (tanSo_khz > tanSoCaiDat);
	}
	//nhấp nháy đèn
	if(cheDoSeg == 3)
	{
		if(++dem_100ms == 100)
		{
			dem_100ms = 0;
			flagDenBat = !flagDenBat;
		}
	}
	else
	{
		dem_100ms = 0;
		flagDenBat = 0;
	}
}

Rơ-le, EEPROM

Lưu ý: EEPROM lưu số lần bật/tắt rơ-le, không chỉ là số lần bật. Cần kiểm tra trùng lặp để tránh kích hoạt rơ-le nhiều lần.


idata u8 demRơle;           //số lần bật/tắt rơ-le

void XuLySong()
{
	khoangCachCm = DocSong() + 2;
	flagKhoangCach = (khoangCachCm > khoangCachM_10x*10);
}

void XuLyLed()
{
	idata bit daDemRơle;//cờ đã đếm rơ-le
	/*rơ-le*/
	if(!daDemRơle && flagKhoangCach)
	{
		daDemRơle = 1;
		demRơle++;
	}
	else if(daDemRơle && !flagKhoangCach)
	{
		daDemRơle = 0;
		demRơle++;
	}
	Rơle(flagKhoangCach);
	GhiEEPROM(&demRơle,0,1);
}

PWM

Xuất xung với tần số 1KHz, tương ứng với thời gian 1ms. Tỷ lệ duty cycle 80% và 20% có nghĩa là trong 1ms, thời gian mức cao chiếm 80% và 20% chu kỳ. Do đó, cần sử dụng timer để định thời 100us, tức là cho timer 2 ngắt 100us một lần để chuyên dụng cho PWM.


idata u8 mucPWM;            //tỷ lệ duty cycle PWM
idata u8 demPWM;			   //đếm thời gian PWM

void XuLyLed()
{
	/*MOTOR*/
	mucPWM = flagTanSo ? 8 : 2;
}

void KhoiDongTimer2(void)		//100 micro giây @12.000MHz
{
	AUXR &= 0xFB;			//chế độ đồng hồ timer 12T
	T2L = 0x9C;				//giá trị khởi tạo
	T2H = 0xFF;				//giá trị khởi tạo
	AUXR |= 0x10;			//bắt đầu timer 2
	IE2 |= 0x04;			//kích hoạt ngắt timer 2
}

void NgatTimer2(void) interrupt 12
{
	if(++demPWM == 10)
		demPWM = 0;
	MayQuay(demPWM < mucPWM);
}

Mã nguồn đầy đủ

Thêm độ trễ vào hàm xử lý nút bấm và mạch 7-segment, và thêm hàm xử lý sóng siêu âm và IIC vào hàm xử lý dữ liệu cho mạch 7-segment để chương trình có thể chạy.


#include <Init.h>
#include <led.h>
#include <key.h>
#include <seg.h>
#include <wave.h>
#include <iic.h>

typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long int u32;
/*độ trễ*/
idata u8 delayKey;              //độ trễ nút bấm 10ms
idata u8 delaySeg;			   //độ trễ mạch 7-segment 200ms
/*nút bấm*/
idata u8 giaTriNhan, nhanXuong, nhanLen, nhanCu;
idata bit flagNhanDai;        //cờ nhấn giữ
idata u16 dem_1000ms;         //giữ 1s
/*mạch 7-segment*/
idata u8 viTriSeg;
pdata u8 bufSeg[8] = {10,10,10,10,10,10,10,10};
pdata u8 dauChamSeg[8] = {0,0,0,0,0,0,0,0};
idata u8 cheDoSeg;        	   //trang chủ 0-tần số 1-độ ẩm 2-khoảng cách 3-tham số
idata u8 cheDoCaiDat;        	   //trang tham số 0-tần số 1-độ ẩm 2-khoảng cách
idata bit flagKhoangCach; 	   //cờ chế độ khoảng cách 0-cm 1-m
idata bit flagTanSo;     	   //cờ chế độ tần số 0-hz 1-khz
/*tần số*/
idata u16 tanSo, dem_1s; 	   //tần số
idata float tanSo_khz;
idata float tanSoCaiDat = 9; 	   //tham số tần số, giá trị ban đầu 9khz, phạm vi 1.0~12.0
idata bit flagTanSo;           //cờ tần số lớn hơn tham số
/*độ ẩm*/
idata u8 doAm;      	   //độ ẩm
idata u8 doAmCaiDat = 40;	   //tham số độ ẩm, giá trị ban đầu 40, phạm vi 10~60
idata bit flagDoAm;       //cờ độ ẩm lớn hơn tham số
/*cảm biến siêu âm*/
idata u8 khoangCachCm;     	   //đo khoảng cách cm
idata u8 khoangCachM_10x = 6;   //tham số siêu âm, giá trị ban đầu 0.6m, phạm vi 0.1~1.2m
idata bit flagKhoangCach;       //cờ khoảng cách lớn hơn tham số
/*đèn chỉ thị*/
pdata u8 led[8] = {0,0,0,0,0,0,0,0};
idata bit flagDenBat;            //cờ nhấp nháy đèn
idata u8 dem_100ms;           //nhấp nháy 1 lần/100ms
idata u8 demRơle;           //số lần bật/tắt rơ-le
idata u8 mucPWM;            //tỷ lệ duty cycle PWM
idata u8 demPWM;			   //đếm thời gian PWM

void XuLyNhan()
{
	delayKey= 1;
	giaTriNhan = DocNhan();
	nhanXuong = giaTriNhan & ~nhanCu;
	nhanLen = ~giaTriNhan & nhanCu;
	nhanCu = giaTriNhan;
	
	if(cheDoSeg == 1)//trên trang độ ẩm, nhấn giữ để xóa số lần rơ-le
	{
		if(nhanXuong == 7)
			flagNhanDai = 1;
		if(nhanLen == 7)
		{
			flagNhanDai = 0;
			if(dem_1000ms >= 1000)
			{
				demRơle = 0;
			}
		}
	}

	switch(nhanXuong)
	{
		case 4:
			if(++cheDoSeg == 4)
				cheDoSeg = 0;
			if(cheDoSeg == 0)
				cheDoCaiDat = 0;
		break;
			
		case 5:
			if(cheDoSeg == 3)
				if(++cheDoCaiDat == 3)
					cheDoCaiDat = 0;
		break;
		
		case 6:
			if(cheDoSeg == 2)
				flagKhoangCach = !flagKhoangCach;
			else if(cheDoSeg == 3)//+
			{
				if(!cheDoCaiDat)//tham số tần số tăng 0.5 mỗi lần
				{
					tanSoCaiDat += 0.5;
					if(tanSoCaiDat == 12.5)
						tanSoCaiDat = 1.0;
				}
				else if(cheDoCaiDat == 1)//tham số độ ẩm tăng 10 mỗi lần
				{
					doAmCaiDat += 10;
					if(doAmCaiDat == 70)
						doAmCaiDat = 10;
				}
				else//tham số khoảng cách tăng 0.1 mỗi lần (tăng 1)
				{
					if(++khoangCachM_10x == 13)
						khoangCachM_10x = 1;
				}
			}
		break;
		
		case 7:
			if(!cheDoSeg)
				flagTanSo = !flagTanSo;
			else if(cheDoSeg == 3)//-
			{
				if(!cheDoCaiDat)//tham số tần số giảm 0.5 mỗi lần
				{
					tanSoCaiDat -= 0.5;
					if(tanSoCaiDat == 0.5)
						tanSoCaiDat = 12.0;
				}
				else if(cheDoCaiDat == 1)//tham số độ ẩm giảm 10 mỗi lần
				{
					doAmCaiDat -= 10;
					if(doAmCaiDat == 0)
						doAmCaiDat = 60;
				}
				else//tham số khoảng cách giảm 0.1 mỗi lần (giảm 1)
				{
					if(--khoangCachM_10x == 0)
						khoangCachM_10x = 12;
				}
			}
		break;
	}
}

void XuLySeg()
{
	switch(cheDoSeg)
	{	
		case 0://trang tần số
			bufSeg[0] = 11;//F
			bufSeg[1] = 10;
			bufSeg[2] = 10;
			dauChamSeg[6] = flagTanSo;
			if(!flagTanSo)
			{
					bufSeg[3] = (tanSo/10000%10)?tanSo/10000%10:10;
					bufSeg[4] = (tanSo/1000%10==0&&bufSeg[3]==10)?10:tanSo/1000%10;
					bufSeg[5] = (tanSo/100%10==0&&bufSeg[4]==10)?10:tanSo/100%10;
					bufSeg[6] = (tanSo/10%10==0&&bufSeg[5]==10)?10:tanSo/10%10;
					bufSeg[7] = tanSo%10;
			}
			else
			{
				bufSeg[3] = 10;
				bufSeg[4] = 10;
				bufSeg[5] = (u8)tanSo_khz / 10 % 10;
				if(!bufSeg[5]) bufSeg[5] = 10;
				bufSeg[6] = (u8)tanSo_khz % 10;
				bufSeg[7] = (u8)(tanSo_khz * 10) % 10;
			}
		break;
			
		case 1://trang độ ẩm
			bufSeg[0] = 12;//H
			bufSeg[3] = 10;
			bufSeg[4] = 10;
			bufSeg[5] = 10;
			bufSeg[6] = doAm / 10;
			bufSeg[7] = doAm % 10;
			dauChamSeg[6] = 0;
		break;
		
		case 2://trang khoảng cách
			bufSeg[0] = 13;//A
			if(!flagKhoangCach)//cm
			{
				if(khoangCachCm < 10)
				{
					bufSeg[5] = 10;
					bufSeg[6] = 10;
					bufSeg[7] = khoangCachCm % 10;
				}
				else
				{
					bufSeg[5] = khoangCachCm / 100 ? khoangCachCm / 100 : 10;
					bufSeg[6] = khoangCachCm / 10 % 10;
					bufSeg[7] = khoangCachCm % 10;
				}
				dauChamSeg[5] = 0;
			}
			else//m
			{
				bufSeg[5] = khoangCachCm / 100;
				bufSeg[6] = khoangCachCm / 10 % 10;
				bufSeg[7] = khoangCachCm % 10;
				dauChamSeg[5] = 1;
			}
		break;
			
		case 3://trang tham số
			bufSeg[0] = 14;//P
			bufSeg[1] = cheDoCaiDat + 1;
			bufSeg[2] = 10;
			bufSeg[3] = 10;
			bufSeg[4] = 10;
			switch(cheDoCaiDat)
			{
				case 0://tham số tần số
					bufSeg[5] = (u8)tanSoCaiDat / 10 ? tanSoCaiDat / 10 : 10;
					bufSeg[6] = (u8)tanSoCaiDat % 10;
					bufSeg[7] = (u8)(tanSoCaiDat * 10) % 10;
					dauChamSeg[6] = 1;
				break;
				
				case 1://tham số độ ẩm
					bufSeg[5] = 10;
					bufSeg[6] = doAmCaiDat / 10;
					bufSeg[7] = doAmCaiDat % 10;
					dauChamSeg[6] = 0;
				break;
				
				case 2://tham số khoảng cách
					bufSeg[6] = khoangCachM_10x / 10;
					bufSeg[7] = khoangCachM_10x % 10;
					dauChamSeg[6] = 1;
				break;
			}
		break;
	}
}

void XuLySong()
{
	khoangCachCm = DocSong() + 2;
	flagKhoangCach = (khoangCachCm > khoangCachM_10x*10);
}

void XuLyLed()
{
	u8 i;
	idata bit daDemRơle;//cờ đã đếm rơ-le
	/*rơ-le*/
	if(!daDemRơle && flagKhoangCach)
	{
		daDemRơle = 1;
		demRơle++;
	}
	else if(daDemRơle && !flagKhoangCach)
	{
		daDemRơle = 0;
		demRơle++;
	}
	Rơle(flagKhoangCach);
	/*Led*/
	if(cheDoSeg != 3)
	{
		for(i = 0; i < 3; i++)
			led[i] = (i == cheDoSeg);
	}
	else
	{
		for(i = 0; i < 3; i++)
			led[i] = (i == cheDoCaiDat && flagDenBat);
	}
	led[3] = flagTanSo;
	led[4] = flagDoAm;
	led[5] = flagKhoangCach;
	HienThiLed(led);
	/*MOTOR*/
	mucPWM = flagTanSo ? 8 : 2;
}

void XuLyIIC()
{
	float dat;
	/*AD*/
	float RB2 = DocAD() / 51.0;
	if(RB2 >= 5.0)
		doAm = 100;
	else
		doAm = 20 * RB2;
	/*DA*/
	if(doAm <= doAmCaiDat)
		dat = 1.0;
	else if(doAm >= 80)
		dat = 5.0;
	else
		dat = 4.0/(80-doAmCaiDat)*doAm+1-4.0*doAmCaiDat/(80-doAmCaiDat);
	GhiDA(dat * 51);
	flagDoAm = (doAm > doAmCaiDat);
	/*EEPROM*/
	GhiEEPROM(&demRơle,0,1);
}

void KhoiDongTimer0(void)		//0 micro giây @12.000MHz
{
	TMOD &= 0xF0;			//cài đặt chế độ timer
	TMOD |= 0x05;			//cài đặt chế độ timer
	TL0 = 0;				//giá trị khởi tạo
	TH0 = 0;				//giá trị khởi tạo
	TF0 = 0;				//xóa cờ TF0
	TR0 = 1;				//bắt đầu timer 0
}

void KhoiDongTimer1(void)		//1 mili giây @12.000MHz
{
	AUXR &= 0xBF;			//chế độ đồng hồ timer 12T
	TMOD &= 0x0F;			//cài đặt chế độ timer
	TL1 = 0x18;				//giá trị khởi tạo
	TH1 = 0xFC;				//giá trị khởi tạo
	TF1 = 0;				//xóa cờ TF1
	TR1 = 1;				//bắt đầu timer 1
	ET1 = 1;				//kích hoạt ngắt timer 1
	EA = 1;
}

void KhoiDongTimer2(void)		//100 micro giây @12.000MHz
{
	AUXR &= 0xFB;			//chế độ đồng hồ timer 12T
	T2L = 0x9C;				//giá trị khởi tạo
	T2H = 0xFF;				//giá trị khởi tạo
	AUXR |= 0x10;			//bắt đầu timer 2
	IE2 |= 0x04;			//kích hoạt ngắt timer 2
}

void NgatTimer1(void) interrupt 3
{
	if(++viTriSeg == 8)
		viTriSeg = 0;
	HienThiSeg(viTriSeg, bufSeg[viTriSeg], dauChamSeg[viTriSeg]);
	//NE555
	if(++dem_1s == 1000)
	{
		dem_1s = 0;
		tanSo = (TH0 << 8) | TL0;
		tanSo_khz = tanSo / 1000.0;
		TH0 = TL0 = 0;
		flagTanSo = (tanSo_khz > tanSoCaiDat);
	}
	//nhấp nháy đèn
	if(cheDoSeg == 3)
	{
		if(++dem_100ms == 100)
		{
			dem_100ms = 0;
			flagDenBat = !flagDenBat;
		}
	}
	else
	{
		dem_100ms = 0;
		flagDenBat = 0;
	}
	//đếm thời gian nhấn giữ nút
	if(flagNhanDai)
	{
		if(++dem_1000ms >= 1000)
			dem_1000ms = 1000;
	}
	else
		dem_1000ms = 0;
}

void NgatTimer2(void) interrupt 12
{
	if(++demPWM == 10)
		demPWM = 0;
	MayQuay(demPWM < mucPWM);
}

void main()
{
	SystemInit();
	KhoiDongTimer0();
	KhoiDongTimer1();
	KhoiDongTimer2();
	while(1)
	{
		//...
	}
}

Thẻ: vi điều khiển Lantiao Cup C PWM cảm biến siêu âm

Đăng vào ngày 28 tháng 6 lúc 08:28