/******************************************************************************
linux设备驱动开发之《报警器项目》源代码
*****************************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define KEY1 1
#define KEY2 2
#define KEY3 3
#define KEY4 4
#define KEY5 5
#define KEY6 6
#define NOKEY 0
#define MYKEY "/dev/key_driver"
#define MYLED "/dev/led_driver"
#define MYPWM "/dev/pwm_driver"
#define MYRTC "/dev/rtc_driver"
#define MYADC "/dev/adc_driver"
volatile unsigned int pwm_alarm_flag=0; //蜂鸣器的报警方式(默认为0 不叫)
volatile unsigned int led_alarm_flag=0;//LED的报警方式
volatile unsigned int key_alarm_flag=0;//KEY的报警方式
volatile unsigned int rtc_alarm_flag = 0;//关闭rtc报警
volatile unsigned int adc_alarm_flag=0; // ADC电阻警告
volatile unsigned int mask_all_alarm=0; //屏蔽所有的警告方式
volatile unsigned int rtc_submenu_flag=0;//进入rtc菜单项
volatile unsigned int rtc_clock_alarm_flag=0;//RTC //clock闹铃
volatile unsigned int display_menu_flag=0;//display 主菜单项
volatile unsigned int display_menu_first_flag=0;
volatile unsigned int display_menu_first_flag2=0;
volatile unsigned int display_sub_menu_flag=0;
volatile unsigned int pause_clock_alarm_flag=0;
int fd; //MYKEY用的合局变量
void display_main_menu(void)
{
printf("=========================================\n");
printf("=========Alarm made by hui=new===========\n");
printf("##*welcome !the functions as follow:***##\n");
printf("##* key1 : alarm1 *##\n");
printf("##* key2 : alarm2 *##\n");
printf("##* key3 : rtc submenu: *##\n");
printf("##* 1.display date and time *##\n");
printf("##* 2.setting date and time *##\n");
printf("##* 3.setting alarm clock *##\n");
printf("##* key4 : enable all alarm way *##\n");
printf("##* key5 : disable all alarm way *##\n");
printf("##* key6 : pause all alarm way *##\n");
printf("=================good-bye================\n");
}
void display_sub_menu(void)
{
//日期和时间闹钟菜单
printf("=============================\n");
printf("====display rtc sub menu:====\n");
printf("**1.display date and time **\n"); //显示日期和时间
printf("**2.setting date and time **\n"); //设置日期和时间
printf("**3.setting alarm clock **\n"); //设置闹钟
printf("**4.display alarm time **\n"); //显示设置闹钟的时间
printf("**5.stop alarm clock **\n"); // 停止闹钟 stop clock
printf("**6.cacel clock time **\n"); //取消闹钟
printf("**7.return **\n");
printf("=============================\n");
}
void Delay_MS( unsigned int time) //50 ns
{
unsigned int i,j;
for ( i=0; i<time; i++)
{
for(j=0;j<30000;j++)
{
}
}
}
//函数:KeyScan
//功能:读取按下的按键,并返回按键的标记号
//参数:无
//返回值:int
int KeyScan(void)
{
volatile unsigned int temp,status;
int key=NOKEY; //记录press 的按键
/*注意:GPGDAT先取反,press后GPGDAT原来为0,取反后为1*/
/*再& ,取出到底是哪一位按下,按下的为1*/
read(fd,&status,4);
temp = (~status ) & ((1<<11)|(1<<7)|(1<<6)|(1<<5)|(1<<3)|(1<<0));
switch(temp)
{
case (1<<0): //KEY1
{
key = KEY1;
return key;
}
case (1<<3): //KEY2
{
key = KEY2;
return key;
}
case (1<<5): //KEY3
{
key = KEY3;
return key;
}
case (1<<6): //KEY4
{
key = KEY4;
return key;
}
case (1<<7): //KEY5
{
key = KEY5;
return key;
}
case (1<<11): //KEY6
{
key = KEY6;
return key;
}
default: //NOKEY
return NOKEY;
}
}
volatile unsigned int key_old=NOKEY;
volatile unsigned int key_new=NOKEY;
int Get_Keyvalue(void)
{
int key_1=NOKEY;
int key_2=NOKEY;
key_1=KeyScan();
Delay_MS(20);
key_2=KeyScan();
if(key_1 != key_2) //如果按下的key_1和key_2不相等,说明抖动
{
return NOKEY; //就当作没按下
}
else //如果按下的key_1和key_2相等,说明按住不放,重复
{
key_new=key_2;
if(key_new!=key_old) //按下的跟之前那次比较,如果新按的跟旧按下的不相等
{
key_old=key_new; //旧值更新
return key_old; //返回有按下
}
else if(key_new==key_old) //如果新按的跟旧按下的相等
{
return NOKEY; //就当作没按下
}
}
}
//KEY查询模式fd一定要设成共享,否则按键按下没反应
void *pthread_key(void *arg)
{
int i=0;
unsigned int cmd;
unsigned int status;
int key;
int g_led_num;
volatile unsigned int temp;
fd = open(MYKEY,O_RDWR);
if (fd < 0)
{
perror("open device key_driver----");
exit(1);
}
display_menu_flag=1;
while(1)
{
if(display_menu_flag ==1)
{
if(display_menu_first_flag==1)
{
display_main_menu();
}
key = Get_Keyvalue();
if(key ==0)
{
display_menu_first_flag=0;
continue;
}
if(key!=3)
display_main_menu();
if(key==1) //报警方式1
{
//printf("********1**********\n");
printf("key1 press!\n");
if(mask_all_alarm==0)
{
led_alarm_flag = 1;
pwm_alarm_flag=1;
}
}
if(key==2) //报警方式2
{
//printf("********2**********\n");
printf("key2 press!\n");
if(mask_all_alarm==0)
{
led_alarm_flag = 2;
pwm_alarm_flag=2;
}
}
if(key==3)
{
//printf("********3**********\n");
printf("key3 press!\n");
if(display_sub_menu_flag==1) //闹铃退出后按KEY3显示子菜单
{
display_sub_menu();
display_sub_menu_flag=0;
}
rtc_submenu_flag=1; //进入rtc设置子菜单
display_menu_flag=0; //禁止KEY功能
}
if(key==4)//使能所有的报警
{
//printf("********4**********\n");
printf("key4 press!\n");
mask_all_alarm=0; //使能所有的报警
}
if(key==5) //disable 所有的报警
{
//printf("********5**********\n");
printf("key5 press!\n");
led_alarm_flag = 0; //先关闭LED灯
pwm_alarm_flag=0; //先关闭 蜂鸣器响声
rtc_clock_alarm_flag=0; //关闭clock闹铃
adc_alarm_flag = 0;//先关闭ADC电阻报警
mask_all_alarm = 1; //屏蔽所有的报警
}
if(key==6)//暂停所有的报警
{
//printf("*********6**********\n");
printf("key6 press!\n");
led_alarm_flag = 0; //先关闭LED灯
pwm_alarm_flag=0; //pause 蜂鸣器响声
rtc_clock_alarm_flag=0; //关闭clock闹铃
adc_alarm_flag = 0;//先关闭ADC电阻报警
}
}
}
close(fd);
}
void *pthread_led(void *arg)
{
int fd,keynum;
if((fd=open(MYLED, O_RDWR, 0666))<0)
{
perror("open led_driver ERROR!\n");
exit(1);
}
printf("open led_driver success!\n");
while(1)
{
//报警方式1,4个灯亮一秒,再4个灯灭每一秒
if((mask_all_alarm==0)&&(led_alarm_flag==1))
{
ioctl(fd, 1, 1);
ioctl(fd, 1, 2);
ioctl(fd, 1, 3);
ioctl(fd, 1, 4);
//sleep(1);
Delay_MS(200);
ioctl(fd, 0, 1);
ioctl(fd, 0, 2);
ioctl(fd, 0, 3);
ioctl(fd, 0, 4);
//sleep(1);
Delay_MS(200);
}
//报警方式2,1、3灯亮一秒,然后2、4灯再亮一秒
if((mask_all_alarm==0)&&(led_alarm_flag==2))
{
ioctl(fd, 1, 1);
ioctl(fd, 1, 3);
Delay_MS(200);
ioctl(fd, 0, 1);
ioctl(fd, 0, 3);
ioctl(fd, 1, 2);
ioctl(fd, 1, 4);
Delay_MS(200);
ioctl(fd, 0, 2);
ioctl(fd, 0, 4);
}
//报警方式3,1、2亮一秒,然后3、4灯亮一秒,全灭一秒
if((mask_all_alarm==0)&&(adc_alarm_flag==1)) //ADC电阻超值>80%
{
ioctl(fd, 1, 1);
ioctl(fd, 1, 2);
Delay_MS(50);
ioctl(fd, 0, 1);
ioctl(fd, 0, 2);
ioctl(fd, 1, 3);
ioctl(fd, 1, 4);
Delay_MS(50);
ioctl(fd, 0, 3);//全灭一秒
ioctl(fd, 0, 4);
ioctl(fd, 0, 1);
ioctl(fd, 0, 2);
Delay_MS(50);
}
//报警方式4,1、2、3、4轮流亮一秒
if((mask_all_alarm==0)&&(adc_alarm_flag==2))//ADC电阻超值<20%
{
ioctl(fd, 1, 1);
Delay_MS(50);
ioctl(fd, 0, 1);
ioctl(fd, 1, 2);
Delay_MS(50);
ioctl(fd, 0, 2);
ioctl(fd, 1, 3);
Delay_MS(50);
ioctl(fd, 0, 3);
ioctl(fd, 1, 4);
Delay_MS(50);
ioctl(fd, 0, 4);
}
//报警方式5,定时器时间触发, 1、2灯亮一秒,然后3、4灯再亮一秒,
if((mask_all_alarm==0)&&(led_alarm_flag==5))
{
ioctl(fd, 1, 1);
ioctl(fd, 1, 2);
Delay_MS(50);
ioctl(fd, 0, 1);
ioctl(fd, 0, 2);
ioctl(fd, 1, 3);
ioctl(fd, 1, 4);
Delay_MS(50);
ioctl(fd, 0, 3);
ioctl(fd, 0, 4);
}
}
}
void *pthread_pwm(void *arg)
{
int fd,i=0;
#define PWM_ON 1
#define PWM_OFF 0
unsigned int tonefreq[7]={1046,1175,1318,1397,1569,1760,1976};
unsigned int tonefreq2[7]={523,578,659,698,784,880,988};
fd = open(MYPWM,O_RDWR,0666);
if (fd < 0)
{
perror("open device pwm_driver error\n");
exit(1);
}
printf("open /dev/pwm_driver success!\n");
while(1)
{
//报警方式1,响铃1声
if((mask_all_alarm==0)&&(pwm_alarm_flag==1))
{
ioctl(fd, PWM_ON, tonefreq[0]);
Delay_MS(200);
ioctl(fd, PWM_OFF, 0);
Delay_MS(200);
}
//报警方式2,响铃2声
if((mask_all_alarm==0)&&(pwm_alarm_flag==2))
{
ioctl(fd, PWM_ON, tonefreq[1]);
Delay_MS(50);
ioctl(fd, PWM_OFF, 0);
ioctl(fd, PWM_ON, tonefreq[2]);
Delay_MS(50);
ioctl(fd, PWM_OFF,0);
}
//可变电阻达到最大值的80%,报警方式3,响铃3声
if((mask_all_alarm==0)&&(adc_alarm_flag==1))
{
ioctl(fd, PWM_ON, tonefreq[0]);
Delay_MS(50);
ioctl(fd, PWM_OFF, 0);
ioctl(fd, PWM_ON, tonefreq[1]);
Delay_MS(50);
ioctl(fd, PWM_OFF,0);
ioctl(fd, PWM_ON, tonefreq[2]);
Delay_MS(50);
ioctl(fd, PWM_OFF, 0);
}
//可变电阻小于最大值的20%,报警方式4,响铃4声
if((mask_all_alarm==0)&&(adc_alarm_flag==2))
{
ioctl(fd, PWM_ON, tonefreq[3]);
Delay_MS(40);
ioctl(fd, PWM_OFF, 0);
ioctl(fd, PWM_ON, tonefreq[1]);
Delay_MS(40);
ioctl(fd, PWM_OFF,0);
ioctl(fd, PWM_ON, tonefreq[2]);
Delay_MS(40);
ioctl(fd, PWM_OFF, 0);
ioctl(fd, PWM_ON, tonefreq[3]);
Delay_MS(40);
ioctl(fd, PWM_OFF, 0);
}
//定时器时间触发,报警方式5,蜂鸣器响声5
if((mask_all_alarm==0)&&(pwm_alarm_flag==5)) //闹铃
{
ioctl(fd, PWM_ON, tonefreq[3]);
Delay_MS(30);
ioctl(fd, PWM_OFF, 0);
Delay_MS(30);
ioctl(fd, PWM_ON, tonefreq[3]);
Delay_MS(30);
ioctl(fd, PWM_OFF,0);
Delay_MS(30);
ioctl(fd, PWM_ON, tonefreq[3]);
Delay_MS(30);
ioctl(fd, PWM_OFF, 0);
Delay_MS(30);
ioctl(fd, PWM_ON, tonefreq[2]);
Delay_MS(30);
ioctl(fd, PWM_OFF, 0);
Delay_MS(30);
ioctl(fd, PWM_ON, tonefreq[4]);
Delay_MS(30);
ioctl(fd, PWM_OFF, 0);
Delay_MS(30);
}
}
close(fd);
return 0;
}
struct TIME_RTC
{
volatile unsigned int year;
volatile unsigned int mon;
volatile unsigned int day; //周
volatile unsigned int date;
volatile unsigned int hour;
volatile unsigned int min;
volatile unsigned int sec;
}alarm_time;
int fd_rtc; //MYRTC的全局变量
void *pthread_rtc(void *arg)
{
int i=0,ret;
char choice[2]={0};
int year,mon,day,date,hour,min,sec;
struct TIME_RTC rtc_time;
printf("********into pthread_rtc function****\n");
fd_rtc = open(MYRTC,O_RDWR,0666);
if (fd_rtc < 0)
{
perror("open device rtc_driver error\n");
exit(1);
}
printf("open /dev/rtc_driver success!\n");
// 1.显示系统时间 2.设置日期和时间 3.设置闹钟
while(1)
{
if(rtc_submenu_flag==1)
{
display_sub_menu(); //显示设置日期、时间、闹钟菜单
printf("please input choice:");//输入选择菜单项
memset(choice,0,sizeof(choice));
input:scanf("%s",choice);
if(strcmp("1",choice)==0)
{
ret = read(fd_rtc,&rtc_time,sizeof(struct TIME_RTC));
printf("the time is :\n");
printf("***************************\n");
printf("**date:%d - %d -%d\n",rtc_time.year,rtc_time.mon,rtc_time.date);
printf("**workday:%d\n",rtc_time.day);
printf("**time:%d : %d : %d\n",rtc_time.hour,rtc_time.min,rtc_time.sec);
printf("***************************\n");
}
else if(strcmp("2",choice)==0)
{
printf("please input the date and time that you will set!!\n");
printf("please input year: ");
scanf("%d",&rtc_time.year);
if(rtc_time.year<1||rtc_time.year>=100)
{
printf("wrong!set year recover: ");
scanf("%d",&rtc_time.year);
}
printf("please input mon: ");
scanf("%d",&rtc_time.mon);
if(rtc_time.mon<1||rtc_time.mon>12)
{
printf("wrong!set mon recover: ");
scanf("%d",&rtc_time.mon);
}
printf("please input date: ");
scanf("%d",&rtc_time.date);
if(rtc_time.date<1||rtc_time.date>31)
{
printf("wrong!set date recover: ");
scanf("%d",&rtc_time.date);
}
printf("please input day: ");
scanf("%d",&rtc_time.day);
if(rtc_time.day<1||rtc_time.day>31)
{
printf("wrong!set day recover: ");
scanf("%d",&rtc_time.day);
}
printf("please input hour: ");
scanf("%d",&rtc_time.hour);
if(rtc_time.hour<1||rtc_time.hour>24)
{
printf("wrong!set hour recover: ");
scanf("%d",&rtc_time.hour);
}
printf("please input min: ");
scanf("%d",&rtc_time.min);
if(rtc_time.min<1||rtc_time.min>60)
{
printf("wrong!set min recover: ");
scanf("%d",&rtc_time.min);
}
printf("please input sec: ");
scanf("%d",&rtc_time.sec);
if(rtc_time.sec<1||rtc_time.sec>60)
{
printf("wrong!set sec recover: ");
scanf("%d",&rtc_time.sec);
}
ret= write(fd_rtc,&rtc_time,sizeof(struct TIME_RTC));
if(ret<0)
{
printf("write time error!\n");
exit(1);
}
printf("\ndate and day is setting OK now!!\n");
}
else if(strcmp("3",choice)==0)
{
printf("please input the clock alarm time that you will set!!\n");
printf("set clock alarm year: ");
scanf("%d",&year);
if(year<1||year>=100)
{
printf("wrong!set year recover: ");
scanf("%d",&year);
}
printf("set clock alarm mon: ");
scanf("%d",&mon);
if(mon<1||mon>12)
{
printf("wrong!set mon recover: ");
scanf("%d",&mon);
}
printf("set clock alarm date: ");
scanf("%d",&date);
if(date<1||date>31)
{
printf("wrong!set date recover: ");
scanf("%d",&date);
}
printf("set clock alarm hour: ");
scanf("%d",&hour);
if(hour<1||hour>24)
{
printf("wrong!set hour recover: ");
scanf("%d",&hour);
}
printf("set clock alarm min: ");
scanf("%d",&min);
if(min<1||min>60)
{
printf("wrong!set min recover: ");
scanf("%d",&min);
}
printf("set clock alarm sec: ");
scanf("%d",&sec);
if(sec<1||sec>60)
{
printf("wrong!set sec recover: ");
scanf("%d",&sec);
}
alarm_time.year = year;
alarm_time.mon = mon;
alarm_time.date = date;
alarm_time.hour = hour;
alarm_time.min = min;
alarm_time.sec = sec;
printf("\nclock alarm date and time:\n");
printf("date: 20%d - %d -%d\n",alarm_time.year,alarm_time.mon,alarm_time.date);
printf("time: %d : %d : %d\n",alarm_time.hour,alarm_time.min,alarm_time.sec);
rtc_clock_alarm_flag=1;//clock闹铃打开
}
else if(strcmp("4",choice)==0)//查看设置的闹钟时间
{
printf("\nclock alarm date and time:\n");
printf("date: 20%d - %d -%d\n",alarm_time.year,alarm_time.mon,alarm_time.date);
printf("time: %d : %d : %d\n",alarm_time.hour,alarm_time.min,alarm_time.sec);
}
else if(strcmp("5",choice)==0)//停止闹钟
{
pwm_alarm_flag=0; //pwm蜂鸣器响声5
display_sub_menu_flag=0; //优化用键盘停止闹钟时不重复显示子菜单(按键停止闹钟时会影响)
display_menu_first_flag2=1; //优化用键盘停止闹钟时不重复显示主菜单
}
else if(strcmp("6",choice)==0)//取消闹钟
{
rtc_clock_alarm_flag=0;
}
else if(strcmp("7",choice)==0)
{
if(display_menu_first_flag2==1) //优化用键盘停止闹钟时不重复显示主菜单
{
display_main_menu();
display_menu_first_flag2=0;
}
display_menu_flag=1; //显示主菜单,进入主菜单
display_menu_first_flag=1; //退出时显示主菜单
rtc_submenu_flag=0; //退出rtc子菜单
}
else
{
printf("Input Wrong!! \nplease choice again: ");
goto input;
}
}
}
close(fd_rtc);
return 0;
}
void *pthread_alarm_clock(void *arg)
{
int ret,i;
struct TIME_RTC local_time;//local_time local_time
while(1)
{
if((rtc_clock_alarm_flag==1)&&(mask_all_alarm==0)) //RTC报警是有打开
{
ret = read(fd_rtc,&local_time,sizeof(struct TIME_RTC));
if(ret<0)
{
printf("write alarm_time error!\n");
exit(1);
}
if(local_time.year != alarm_time.year)
{
continue;
}
if(local_time.mon != alarm_time.mon)
{
continue;
}
if(local_time.date != alarm_time.date)
{
continue;
}
if(local_time.hour != alarm_time.hour)
{
continue;
}
if(local_time.min != alarm_time.min)
{
continue;
}
if(local_time.sec != alarm_time.sec)
{
continue;
}
pwm_alarm_flag=5; //pwm蜂鸣器响声5
rtc_clock_alarm_flag=0;
//定时器时间触发,报警方式5, 1、2灯亮一秒,然后3、4灯再亮一秒,蜂鸣器响声5
display_menu_flag=1;//开户KEY按键功能
display_sub_menu_flag=1;//显示子菜单
}
}
}
void *pthread_adc(void *arg)
{
int fd;
unsigned int value =-1;
unsigned int value_old = -1;
fd = open(MYADC,O_RDWR,0666);
if (fd < 0)
{
perror("open device adc_driver error\n");
exit(1);
}
int value1,value2;
printf("open /dev/rtc_driver success!\n");
while(1)
{
read(fd,&value,sizeof(int));
value1=value;
Delay_MS(10);
read(fd,&value,sizeof(int));
value2=value;
if(value > 818)
{//可变电阻达到最大值的80%,报警方式3
adc_alarm_flag = 1; //ADC报警1
if(value != value_old)
{
printf("value bigger 818 wrong !!adc value =%d:>%80\n",value);
}
}
else if(value < 204)
{//可变电阻小于最大值的20%,报警方式4,
adc_alarm_flag = 2; //ADC报警2
if(value != value_old)
{
printf("value little 204 wrong !!adc value =%d:<%20\n",value);
}
}
else
{ int temp;
adc_alarm_flag = 0; //ADC报警3
temp=value2 - value1;
if(temp<0)
temp = temp*(-1);
if(temp>5 )
{
printf("OK!,value2 != value1 !!\nthe value is : %d\n",value);
}
}
}
if(close(fd)<0)
{
perror("close adc error\n");
}
}
int main(void)
{
int ret;
pthread_t led_id,pwm_id,key_id,rtc_id,adc_id,alarm_clock_id;
pwm_alarm_flag=0; //蜂鸣器的报警方式(默认为0 不叫)
led_alarm_flag=0;//LED的报警方式
key_alarm_flag=0;//KEY的报警方
mask_all_alarm=0; //屏蔽所有的警告方式
display_main_menu(); //显示主菜单
ret = pthread_create(&key_id, NULL,(void *)pthread_key, NULL);
if(ret !=0)
{
printf("Creat KEY pthread error!\n");
exit(1);
}
ret = pthread_create(&led_id, NULL, (void *)pthread_led, NULL);
if(ret !=0)
{
printf("Creat led pthread error!\n");
exit(1);
}
ret = pthread_create(&pwm_id, NULL, (void *)pthread_pwm, NULL);
if(ret !=0)
{
printf("Creat PWM pthread error!\n");
exit(1);
}
ret = pthread_create(&rtc_id, NULL, (void *)pthread_rtc, NULL);
if(ret !=0)
{
printf("Creat RTC pthread error!\n");
exit(1);
}
ret = pthread_create(&adc_id, NULL, (void *)pthread_adc, NULL);
if(ret !=0)
{
printf("Creat ADC pthread error!\n");
exit(1);
}
ret = pthread_create(&alarm_clock_id, NULL, (void *)pthread_alarm_clock, NULL);
if(ret !=0)
{
printf("Creat pthread_alarm_clock pthread error!\n");
exit(1);
}
//等待子线各结束
pthread_join(key_id, NULL);
pthread_join(led_id, NULL);
pthread_join(pwm_id, NULL);
pthread_join(rtc_id, NULL);
pthread_join(adc_id, NULL);
pthread_join(alarm_clock_id, NULL);
return 0;
}