上个月刚做的关于Ds1302时钟和数模转换的设计,
检测电池电压,自我供电的 包含源码和工程。
单片机源程序如下:
- /*
- *******************************************************************************
- *
- * 文件名:main.c
- 用DS1302实现简易电子钟
- * 用液晶显示日期时间,并可通过按键校时
- *******************************************************************************
- */
- #include <reg52.h>
- struct sTime { //日期时间结构体定义
- unsigned int year;
- unsigned char mon;
- unsigned char day;
- unsigned char hour;
- unsigned char min;
- unsigned char sec;
- unsigned char week;
- };
- bit flag300ms = 1; //300ms定时标志
- bit flag200ms = 1; //200ms定时标志
- unsigned char T0RH = 0; //T0重载值的高字节
- unsigned char T0RL = 0; //T0重载值的低字节
- struct sTime bufTime; //日期时间缓冲区
- unsigned char setIndex = 0; //时间设置索引
- void ConfigTimer0(unsigned int ms);
- unsigned char GetADCValue(unsigned char chn);
- void ValueToString(unsigned char *str, unsigned char val);
- extern void I2CStart();
- extern void I2CStop();
- extern unsigned char I2CReadACK();
- extern unsigned char I2CReadNAK();
- extern bit I2CWrite(unsigned char dat);
- extern void InitLcd1602();
- extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
- void ConfigTimer0(unsigned int ms);
- void RefreshTimeShow();
- extern void InitDS1302();
- extern void GetRealTime(struct sTime *time);
- extern void SetRealTime(struct sTime *time);
- extern void KeyScan();
- extern void KeyDriver();
- extern void InitLcd1602();
- extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);
- extern void LcdSetCursor(unsigned char x, unsigned char y);
- extern void LcdOpenCursor();
- extern void LcdCloseCursor();
- void main()
- {
- unsigned char psec=0xAA; //秒备份,初值AA确保首次读取时间后会刷新显示
- unsigned char val;
- unsigned char str[10];
- EA = 1; //开总中断
- ConfigTimer0(1); //T0定时1ms
- InitDS1302(); //初始化实时时钟
- InitLcd1602(); //初始化液晶
-
- //初始化屏幕上固定不变的内容
- LcdShowStr(0, 0, "20 - - ");
- LcdShowStr(1, 1, " : : ");
- LcdShowStr(11, 0, "Vol"); //显示通道指示
-
- while (1)
- {
- KeyDriver(); //调用按键驱动
- if (flag200ms && (setIndex == 0))
- { //每隔200ms且未处于设置状态时,
- flag200ms = 0;
- GetRealTime(&bufTime); //获取当前时间
- if (psec != bufTime.sec) //检测到时间有变化时刷新显示
- {
- RefreshTimeShow();
- psec = bufTime.sec; //用当前值更新上次秒数
- }
- }
- if (flag300ms)
- {
- flag300ms = 0;
- //显示通道0的电压
- val = GetADCValue(0); //获取ADC通道0的转换值
- ValueToString(str, val); //转为字符串格式的电压值
- LcdShowStr(11, 1, str); //显示到液晶上
- //显示通道1的电压
- /*val = GetADCValue(1);
- ValueToString(str, val);
- LcdShowStr(6, 1, str);
- //显示通道3的电压
- val = GetADCValue(3);
- ValueToString(str, val);
- LcdShowStr(12, 1, str); */
- }
- }
- }
- /* 将一个BCD码字节显示到屏幕上,(x,y)-屏幕起始坐标,bcd-待显示BCD码 */
- void ShowBcdByte(unsigned char x, unsigned char y, unsigned char bcd)
- {
- unsigned char str[4];
-
- str[0] = (bcd >> 4) + '0';
- str[1] = (bcd&0x0F) + '0';
- str[2] = '\0';
- LcdShowStr(x, y, str);
- }
- /* 刷新日期时间的显示 */
- void RefreshTimeShow()
- {
- ShowBcdByte(2, 0, bufTime.year);
- ShowBcdByte(5, 0, bufTime.mon);
- ShowBcdByte(8, 0, bufTime.day);
- ShowBcdByte(1, 1, bufTime.hour);
- ShowBcdByte(4, 1, bufTime.min);
- ShowBcdByte(7, 1, bufTime.sec);
- }
- /* 刷新当前设置位的光标指示 */
- void RefreshSetShow()
- {
- switch (setIndex)
- {
- case 1: LcdSetCursor(2, 0); break;
- case 2: LcdSetCursor(3, 0); break;
- case 3: LcdSetCursor(5, 0); break;
- case 4: LcdSetCursor(6, 0); break;
- case 5: LcdSetCursor(8, 0); break;
- case 6: LcdSetCursor(9, 0); break;
- case 7: LcdSetCursor(1, 1); break;
- case 8: LcdSetCursor(2, 1); break;
- case 9: LcdSetCursor(4, 1); break;
- case 10: LcdSetCursor(5, 1); break;
- case 11: LcdSetCursor(7, 1); break;
- case 12: LcdSetCursor(8, 1); break;
- default: break;
- }
- }
- /* 递增一个BCD码的高位 */
- unsigned char IncBcdHigh(unsigned char bcd)
- {
- if ((bcd&0xF0) < 0x90)
- bcd += 0x10;
- else
- bcd &= 0x0F;
-
- return bcd;
- }
- /* 递增一个BCD码的低位 */
- unsigned char IncBcdLow(unsigned char bcd)
- {
- if ((bcd&0x0F) < 0x09)
- bcd += 0x01;
- else
- bcd &= 0xF0;
-
- return bcd;
- }
- /* 递减一个BCD码的高位 */
- unsigned char DecBcdHigh(unsigned char bcd)
- {
- if ((bcd&0xF0) > 0x00)
- bcd -= 0x10;
- else
- bcd |= 0x90;
-
- return bcd;
- }
- /* 递减一个BCD码的低位 */
- unsigned char DecBcdLow(unsigned char bcd)
- {
- if ((bcd&0x0F) > 0x00)
- bcd -= 0x01;
- else
- bcd |= 0x09;
-
- return bcd;
- }
- /* 递增时间当前设置位的值 */
- void IncSetTime()
- {
- switch (setIndex)
- {
- case 1: bufTime.year = IncBcdHigh(bufTime.year); break;
- case 2: bufTime.year = IncBcdLow(bufTime.year); break;
- case 3: bufTime.mon = IncBcdHigh(bufTime.mon); break;
- case 4: bufTime.mon = IncBcdLow(bufTime.mon); break;
- case 5: bufTime.day = IncBcdHigh(bufTime.day); break;
- case 6: bufTime.day = IncBcdLow(bufTime.day); break;
- case 7: bufTime.hour = IncBcdHigh(bufTime.hour); break;
- case 8: bufTime.hour = IncBcdLow(bufTime.hour); break;
- case 9: bufTime.min = IncBcdHigh(bufTime.min); break;
- case 10: bufTime.min = IncBcdLow(bufTime.min); break;
- case 11: bufTime.sec = IncBcdHigh(bufTime.sec); break;
- case 12: bufTime.sec = IncBcdLow(bufTime.sec); break;
- default: break;
- }
- RefreshTimeShow();
- RefreshSetShow();
- }
- /* 递减时间当前设置位的值 */
- void DecSetTime()
- {
- switch (setIndex)
- {
- case 1: bufTime.year = DecBcdHigh(bufTime.year); break;
- case 2: bufTime.year = DecBcdLow(bufTime.year); break;
- case 3: bufTime.mon = DecBcdHigh(bufTime.mon); break;
- case 4: bufTime.mon = DecBcdLow(bufTime.mon); break;
- case 5: bufTime.day = DecBcdHigh(bufTime.day); break;
- case 6: bufTime.day = DecBcdLow(bufTime.day); break;
- case 7: bufTime.hour = DecBcdHigh(bufTime.hour); break;
- case 8: bufTime.hour = DecBcdLow(bufTime.hour); break;
- case 9: bufTime.min = DecBcdHigh(bufTime.min); break;
- case 10: bufTime.min = DecBcdLow(bufTime.min); break;
- case 11: bufTime.sec = DecBcdHigh(bufTime.sec); break;
- case 12: bufTime.sec = DecBcdLow(bufTime.sec); break;
- default: break;
- }
- RefreshTimeShow();
- RefreshSetShow();
- }
- /* 右移时间设置位 */
- void RightShiftTimeSet()
- {
- if (setIndex != 0)
- {
- if (setIndex < 12)
- setIndex++;
- else
- setIndex = 1;
- RefreshSetShow();
- }
- }
- /* 左移时间设置位 */
- void LeftShiftTimeSet()
- {
- if (setIndex != 0)
- {
- if (setIndex > 1)
- setIndex--;
- else
- setIndex = 12;
- RefreshSetShow();
- }
- }
- /* 进入时间设置状态 */
- void EnterTimeSet()
- {
- setIndex = 2; //把设置索引设置为2,即可进入设置状态
- LeftShiftTimeSet(); //再利用现成的左移操作移到位置1并完成显示刷新
- LcdOpenCursor(); //打开光标闪烁效果
- }
- /* 退出时间设置状态,save-是否保存当前设置的时间值 */
- void ExitTimeSet(bit save)
- {
- setIndex = 0; //把设置索引设置为0,即可退出设置状态
- if (save) //需保存时即把当前设置时间写入DS1302
- {
- SetRealTime(&bufTime);
- }
- LcdCloseCursor(); //关闭光标显示
- }
- /* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */
- void KeyAction(unsigned char keycode)
- {
- if ((keycode>='0') && (keycode<='9')) //本例中不响应字符键
- {
- }
- else if (keycode == 0x26) //向上键,递增当前设置位的值
- {
- IncSetTime();
- }
- else if (keycode == 0x28) //向下键,递减当前设置位的值
- {
- DecSetTime();
- }
- else if (keycode == 0x25) //向左键,向左切换设置位
- {
- LeftShiftTimeSet();
- }
- else if (keycode == 0x27) //向右键,向右切换设置位
- {
- RightShiftTimeSet();
- }
- else if (keycode == 0x0D) //回车键,进入设置模式/启用当前设置值
- {
- if (setIndex == 0) //不处于设置状态时,进入设置状态
- {
- EnterTimeSet();
- }
- else //已处于设置状态时,保存时间并退出设置状态
- {
- ExitTimeSet(1);
- }
- }
- else if (keycode == 0x1B) //Esc键,取消当前设置
- {
- ExitTimeSet(0);
- }
- }
- /* 读取当前的ADC转换值,chn-ADC通道号0~3 */
- unsigned char GetADCValue(unsigned char chn)
- {
- unsigned char val;
-
- I2CStart();
- if (!I2CWrite(0x48<<1)) //寻址PCF8591,如未应答,则停止操作并返回0
- {
- I2CStop();
- return 0;
- }
- I2CWrite(0x40|chn); //写入控制字节,选择转换通道
- I2CStart();
- I2CWrite((0x48<<1)|0x01); //寻址PCF8591,指定后续为读操作
- I2CReadACK(); //先空读一个字节,提供采样转换时间
- val = I2CReadNAK(); //读取刚刚转换完的值
- I2CStop();
-
- return val;
- }
- /* ADC转换值转为实际电压值的字符串形式,str-字符串指针,val-AD转换值 */
- void ValueToString(unsigned char *str, unsigned char val)
- {
- //电压值=转换结果*2.5V/255,式中的25隐含了一位十进制小数
- val = (val*50) / 255;
- str[0] = (val/10) + '0'; //整数位字符
- str[1] = '.'; //小数点
- str[2] = (val%10) + '0'; //小数位字符
- str[3] = 'V'; //电压单位
- str[4] = '\0'; //结束符
- }
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei提供下载:
kechuang1.zip
(83.42 KB, 下载次数: 6)
|