精华内容
下载资源
问答
  • 单片机按键扫描

    2020-08-07 09:56:34
    //设置用来作为TIMx时钟频率除数的预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上...
    #include "key.h"
    #include "delay.h"
    #include "led1.h"
    #include "usbio.h"
    #include "led_show.h"
    enum CTRL_MODE control_mode;
    enum RUN_MODE   running_mode;
    extern uint16_t fiber_number ;
    extern int8_t current_led_work;
    extern uint16_t time_level ; //ms
    uint16_t encoder_data;
    uint8_t  encoder_direction;
    
    uint8_t MKEY2_fall_flag = 0;
    uint16_t MKEY2_holdon_ms = 0;
    uint8_t MKEY2UpFlag = 0;
    uint16_t MKEY2UpCnt = 0;
    uint16_t MKEY2SignalCnt = 0;
    uint16_t show_fiber_time = 0;
    
    uint8_t MKEY1_fall_flag = 0;
    uint16_t MKEY1_holdon_ms = 0;
    uint8_t MKEY1UpFlag = 0;
    uint16_t MKEY1UpCnt = 0;
    uint16_t MKEY1SignalCnt = 0;
    
    //按键初始化函数
    void KEY_Init(void) //IO初始化
    { 
     	GPIO_InitTypeDef GPIO_InitStructure;
     
     	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD,ENABLE);//使能PORTA,PORTE时钟
    
    	GPIO_InitStructure.GPIO_Pin  = MKEY2_PIN;//MKEY2
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     	GPIO_Init(MKEY2_GPIO, &GPIO_InitStructure);//初始化GPIOC5
    
    	GPIO_InitStructure.GPIO_Pin  = MKEY1_PIN;//MKEY1
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
     	GPIO_Init(MKEY1_GPIO, &GPIO_InitStructure);//初始化GPIOC4
    
    	GPIO_InitStructure.GPIO_Pin  = MOD_SEL_PIN;//MOD_SEL
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
     	GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC12
    	
    	GPIO_InitStructure.GPIO_Pin  = CODE_A_PIN;//CODE_A
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
     	GPIO_Init(CODE_A_GPIO, &GPIO_InitStructure);//初始化
    	
    	GPIO_InitStructure.GPIO_Pin  = CODE_B_PIN;//CODE_B
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
     	GPIO_Init(CODE_B_GPIO, &GPIO_InitStructure);//初始化
    	
    	delay_ms(20);
    	if(MOD_SEL() == 0 )
    		{
    			control_mode = REMOTE_CONTROL  ;
    		}
    		else if(MOD_SEL() == 1)
    			{
    			control_mode =LOCAL_CONTROL ;
    		} 
    }
    void EXTIX_Init(void)
    {
       	EXTI_InitTypeDef EXTI_InitStructure;
     	  NVIC_InitTypeDef NVIC_InitStructure;
        KEY_Init();	 //	按键端口初始化
      	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);	//使能复用功能时钟
    
       //MKEY2 C.5	  中断线以及中断初始化配置 下降沿触发
      	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);
      	EXTI_InitStructure.EXTI_Line=EXTI_Line5;
      	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
      	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
    		EXTI_InitStructure.EXTI_LineCmd = ENABLE;
      	EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
    
       //MKEY1 C.4	  中断线以及中断初始化配置  下降沿触发	//KEY0
      	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource4);
      	EXTI_InitStructure.EXTI_Line=EXTI_Line4;
      	EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
    
    		//MOD_SEL	B.13  中断线以及中断初始化配置 边沿触发
      	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource13);
      	EXTI_InitStructure.EXTI_Line=EXTI_Line13;
      	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
      	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; //上升沿和下降沿
      	EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
    		
    		//CODE_A	  中断线以及中断初始化配置 下降沿触发
      	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
      	EXTI_InitStructure.EXTI_Line=EXTI_Line1;
      	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
      	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
      	EXTI_Init(&EXTI_InitStructure);	  	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
    //
      	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;			//使能按键MKEY2所在的外部中断通道
      	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
      	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;					//子优先级3
      	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
      	NVIC_Init(&NVIC_InitStructure); 
    
      	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;			//使能按键MKEY1所在的外部中断通道
      	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 
      	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;					//子优先级1 
      	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
      	NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    
      	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;			//使能按键MOD_SEL所在的外部中断通道
      	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 
      	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;					//子优先级0 
      	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
      	NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    		
    		NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;			//使能按键CODE_A所在的外部中断通道
      	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2 
      	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;					//子优先级0 
      	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中断通道
      	NVIC_Init(&NVIC_InitStructure);  	  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    }
    
    //外部中断1服务程序 encoder
    void EXTI1_IRQHandler(void)
    {
    	static int  i = 0, j = 0; 
    	if(EXTI_GetITStatus(EXTI_Line1)!=RESET)//判断某个线上的中断是否发生)
    	{
    		if(control_mode == REMOTE_CONTROL)
    		{	
    			EXTI_ClearITPendingBit(EXTI_Line1); //清除LINE2上的中断标志位  
    			return;
    		}
    		if( CODE_A()== RESET )
    		{
    			running_mode = MANUAL;
    			led_cycle_stot();
    			if(CODE_B()	 != RESET ) //逆时针
    			{		
    				encoder_direction = CCW; 
    				i++;
    				j = 0;
    				if( i >= pulse_for_oneStep)
    				{
    					i = 0;					
    					current_led_work--;
    					if( current_led_work < 1 )
    						current_led_work = fiber_number;
    					led_open_one(current_led_work );	
    				}
    			}
    			else if (CODE_B()	 == RESET ) //顺时针
    			{
    				encoder_direction = CW;
    				j++;
    				i = 0;
    				if( j >= pulse_for_oneStep)
    				{
    					j = 0;	
    					current_led_work++;
    					if( current_led_work > fiber_number )
    						current_led_work = 1;	
    					led_open_one(current_led_work );	
    				}
    			}			
    		}
    		EXTI_ClearITPendingBit(EXTI_Line1); //清除LINE2上的中断标志位  
    		USB_SendData32A(current_led_work  ,"A");
    	}
    
    }
    
    //外部中断5-9服务程序 MKEY2 
    void EXTI9_5_IRQHandler(void)
    {
    	int i  , j= 0;
    	if(EXTI_GetITStatus(EXTI_Line5)!=RESET)//判断某个线上的中断是否发生)
    	{
    		if(control_mode == REMOTE_CONTROL)
    		{	
    			EXTI_ClearITPendingBit(EXTI_Line5); //清除LINE2上的中断标志位  
    			return;
    		}
    		//消抖 倒计时
    		for( i = PSD_Check_Num ; i>0;i-- ){
    			if( MKEY2() == RESET) j++;
    		}
    		
    		if( j == PSD_Check_Num ) {//倒计时结束时间内状态相同  	
    			MKEY2_fall_flag = 1; //生成按键按下标志
    		}			
    		EXTI_ClearITPendingBit(EXTI_Line5); //清除LINE5上的中断标志位  
    	}
    }
    
    //外部中断2服务程序 MKEY1
    void EXTI4_IRQHandler(void)
    {
    	int i  , j= 0;
    	if(EXTI_GetITStatus(EXTI_Line4)!=RESET)//判断某个线上的中断是否发生)
    	{	
    		if(control_mode == REMOTE_CONTROL)
    		{	
    			EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE2上的中断标志位  
    			return;
    		}
    		//消抖 倒计时
    		for( i = PSD_Check_Num ; i>0;i-- ){
    			if( MKEY1() == RESET) j++;
    		}
    		if( j == PSD_Check_Num ) {//倒计时结束时间内状态相同  	
    			MKEY1_fall_flag = 1; //生成按键按下标志
    		}			
    
    			
    		EXTI_ClearITPendingBit(EXTI_Line4); //清除LINE2上的中断标志位  
    	}
    }
    
    //外部中断2服务程序 MOD_SEL
    void EXTI15_10_IRQHandler(void)
    {
    	if(EXTI_GetITStatus(EXTI_Line13)!=RESET)//判断某个线上的中断是否发生
    	{
    		
    		delay_ms(100);//消抖
    		if(MOD_SEL() == 0 )
    		{
    				control_mode = REMOTE_CONTROL;
    				USB_SendData((uint8_t *)"REMOTE",6);
    		}
    		else if(MOD_SEL() == 1)
    			{
    					control_mode = LOCAL_CONTROL;
    			USB_SendData((uint8_t *)"LOCAL",5);
    	
    		}
    		EXTI_ClearITPendingBit(EXTI_Line13); //清除LINE12上的中断标志位  
    	}
    }
    
    
    //用来判断双击
    //通用定时器2中断初始化  
    //这里时钟选择为APB1的2倍,而APB1为36M
    //arr:自动重装值。
    //psc:时钟预分频数
    //这里使用的是定时器2! Tout= ((arr+1)*(psc+1))/Tclk;
    void TIM2_Int_Init(u16 arr,u16 psc)
    {
      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
     
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能
    	
    	//定时器TIM4初始化
    	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
    	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位
     
    	TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新中断
     
    	//中断优先级NVIC设置
    	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  //TIM3中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  //从优先级3级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    	NVIC_Init(&NVIC_InitStructure);  //初始化NVIC寄存器					 
    	TIM_Cmd(TIM2, ENABLE);  
    }
    
    //定时器3中断服务程序
    void TIM2_IRQHandler(void)   //TIM2中断s
    {  	
    	static uint8_t is_show_fiber_num = 0;
    	static uint8_t is_show_time_num = 0;
    	static uint8_t judge_signal_flag1 = 0;
    		static uint8_t judge_signal_flag2 = 0;
    	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)  //检查TIM3更新中断发生与否
    		{			
    			//MKEY2 处理
    			if(MKEY2_fall_flag == 1){//发生按键按下事件
    				is_show_time_num = 0;
    				if(MKEY2() == RESET ) //持续按下
    				{
    					if(MKEY2_holdon_ms <= 2000){
    						MKEY2_holdon_ms ++;
    					}
    					else{   //按键按下到1000ms就判断长按时间成立,生成长按标志 
    						MKEY2_holdon_ms = 0;						
    //						USB_SendData((uint8_t *)"L",1);	
    					}
    				}
    				else{ //按键抬起					
    					if( MKEY2_holdon_ms > 50)
    					{
    						MKEY2_holdon_ms = 0;
    						MKEY2_fall_flag = 0;	
    						judge_signal_flag2 = 1;		//用来判断单击
    						is_show_time_num = 0;
    					//距离上次单击时间在100~500ms之间,则认为发生连击事件
    					if( MKEY2UpCnt > 100 && MKEY2UpCnt < 500 ){						
    						MKEY2UpCnt = 0;
    						MKEY2UpFlag = 0;
    						MKEY2SignalCnt = 0 ;
    						judge_signal_flag2 = 0;
    						
    														
    						MKEY2UpFlag = 1; //用来判断双击
    					}
    					else //按键持续时间小于50ms,忽略 	
    					{
    						MKEY2_holdon_ms = 0;
    						MKEY2_fall_flag = 0;
    					}					
    				}				
    			}
    			if(MKEY2UpFlag){//单击抬起后,启动计数,计数到500ms
    				MKEY2UpCnt ++;				
    			}
    			if(MKEY2UpCnt > 500){
    				MKEY2UpCnt = 0;
    				MKEY2UpFlag = 0;				
    			}						
    			if(judge_signal_flag2 ){
    				MKEY2SignalCnt ++;
    			}				
    			if(MKEY2SignalCnt > 500 ) //是单击事件
    			{
    				MKEY2UpCnt = 0;
    				MKEY2UpFlag = 0;
    				MKEY2SignalCnt = 0 ;
    				judge_signal_flag2 = 0;
    				is_show_fiber_num = 0;	
    				is_show_time_num = 0;	
    			}
    
    
    		}			
    		TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );  //清除TIMx更新中断标志 
    }
    
    
    

     

    展开全文
  • 数字钟是通过计数模拟时钟,将计数值转换成时间形式,以格式时-分-秒在LED数码管上进行显示,并通过按键调节扫描频率,该实验分8个等级,通过对应8个二极管从左至右指示扫描频率越来越高的8中扫描频率。 4.源代码...

    1.单片机外观图
    在这里插入图片描述

    2.相关原理图
    在这里插入图片描述
    3.案例目的
    数字钟是通过计数模拟时钟,将计数值转换成时间形式,以格式时-分-秒在LED数码管上进行显示,并通过按键调节扫描频率,该实验分8个等级,通过对应8个二极管从左至右指示扫描频率越来越高的8中扫描频率。

    4.源代码片段分析
    4.1 导入头文件以及变量定义

    #include<STC15F2K60S2.H>
    #include<intrins.h>
    #define uchar unsigned char
    #define uint unsigned int
    
    sbit led_sel=P2^3;//发光二极管的负极
    sbit key1= P3 ^2; //控制数码管扫描频率
    
    /*---------变量定义---------*/
    //七段码(段选),0-9
    uchar duanxuan[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66,
                        0x6d, 0x7d, 0x07, 0x7f, 0x6f}; 
    
    uchar const line = 0x40; //横杠的七段码
    										
    int key1ActionFlag = 0;     //值为1时表示按键操作
    char timeAddOneFlag = 0;    //标记为1,此时需要秒+1
    int ledActionFlag=0;        //led灯的标志
    uint ledOnFlag = 0;         //led灯亮
    char tubeOnFlag = 0;        //数码管亮
    int myDisplay[8] = {0};     //数码管显示的内容
    int ledValue = 1;           //led显示的数值
    uint currHour = 0;
    uint currMinute = 0;
    uint currSecond = 0;
    uint interCount = 0;
    uint keyDownTime = 0;
    uint scanTime = 1;  //扫描时间
    uint currBit = 0;   //当前显示的位
    

    4.2 数码管代码片段

    /**
     * 数码管设置为显示指定的数值
     */
    void changeAll(long num) {
        int i;
        for (i = 7; i >= 0; --i) {
            int foo = num % 10;
            myDisplay[i] = duanxuan[foo];
            num /= 10;
        }
    }
    /**
     * 改变其中一位的内容
     */
    void change1Bit(int bitNum, int value) {
        myDisplay[bitNum - 1] =duanxuan[value];
    }
    /**
     * 改变其中一位的内容为"-"(设置七段码)
     */
    void setline(int bitNum) {
        myDisplay[bitNum - 1] =line;
    }
    /**
     * 显示数码管
     */
    void showTube() {
        if (tubeOnFlag) {
            switchToTube();
            P0 = 0;
            P2 = currBit; //选定位
            P0 = myDisplay[currBit];//根据位置得出段选的数值
            Delay5us();
        }
    }
    

    4.3 LED灯代码片段

    /**
     * led亮
     */
    void displayLed() {
        if (ledOnFlag) {
            switchToLed();
            P0 = ledValue;
        }
    }
    

    4.5 led灯与数码管的转换函数

    /**
     * 设置ledSel,转化led或数码管设置
     */
    void switchToLed() {
        P0 = 0;
        led_sel = 1;
    }
    
    void switchToTube(){
    led_sel =0;
    }
    void Delay5us()       //@11.0592MHz
    {
        unsigned char i;
    
        _nop_();
        i = 11;
        while (--i);
    }
    

    4.6 按键操作

    /**
     * 按下key1要做的事
     */
    void key1Action() {
        if (key1ActionFlag) {
            if (ledValue == 0x80)
                ledValue = 0x01;
            else
                ledValue <<= 1;
            if (ledValue == 1)
                scanTime = 1;
            else if (ledValue == 2)
                scanTime = 50;
            else if (ledValue == 4)
                scanTime = 100;
            else if (ledValue == 8)
                scanTime = 200;
            else if (ledValue == 16)
                scanTime = 500;
            else if (ledValue == 32)
                scanTime = 1000;
            else if (ledValue == 64)
                scanTime = 2000;
            else if (ledValue == 128)
                scanTime = 5000;
            key1ActionFlag = 0;
        }
    }
    

    4.7如何实现时间自增

    //每0.1毫秒定时器中断
    void Timer0() interrupt 1{
    	static const int KEY_TIME_THRESHOLD = 500;
    	interCount=(interCount+1)%20000;//中断次数,每两秒清空依次
    	//led显示频率低些,这样效果更好
    	if(interCount%12>10){
    	 ledOnFlag = 1;
       tubeOnFlag = 0;
    	}else{
    		ledOnFlag = 0;
       tubeOnFlag = 1;
    	}
    	 // 数码管的扫描
        if (interCount % scanTime == 0)
            currBit = (currBit + 1) % 8;
    		 //读秒
        if (interCount % 10000 == 0)
            timeAddOneFlag = 1;
    		  // 按键功能设置,防抖
        if (key1 == 0) {
            if (keyDownTime < KEY_TIME_THRESHOLD)
                ++keyDownTime;
        } else {
            if (keyDownTime >= KEY_TIME_THRESHOLD)
                key1ActionFlag = 1;
            keyDownTime = 0;
        }
    }
    /**
     * 时间自增1秒
     */
    void addTime() {
        ++currSecond;
        if (currSecond == 60) {
            ++currMinute;
            currSecond = 0;
            if (currMinute == 60) {
                ++currHour;
                currMinute = 0;
                if (currHour == 24)
                    currHour = 0;
                change1Bit(2, currHour % 10);
                change1Bit(1, currHour / 10);
            }
            change1Bit(5, currMinute % 10);
            change1Bit(4, currMinute / 10);
        }
        change1Bit(8, currSecond % 10);
        change1Bit(7, currSecond / 10);
    }
    /**
     * 收到中断的信号(是时候自增时间了)
     */
    void timeSignalHandler() {
        if (timeAddOneFlag) {
            addTime();
            timeAddOneFlag = 0;
        }
    }
    

    4.8 初始化函数

    void init()
    {
    P0M0=0XFF;
    P0M1=0X00;
    P2M0=0X0F;
    P2M1=0X00;
    led_sel=0;  //发光二极管不亮
    	
    //定时器0的初始化
        AUXR |= 0x80;        //辅助寄存器AUXR,设置定时器0不分频 定时器时钟1T模式
        TMOD &= 0xF0;        //设置定时器模式,高位设置定时器1,低位设置定时器0,使得定时器0的GATE为0,即TR0=1时就允许计数
    
        TL0 = 0xAE;        //设置定时器初值
        TH0 = 0xFB;        //64430=65535-1105
    	
    //定时器/计数器0/1控制寄存器TCON格式里的位
        TF0 = 0;        //清除TF0标志,TF0是T0溢出中断标志,
        TR0 = 1;        //定时器0的运行控制位,定时器0开始计时
    
        EA = 1; //打开总的中断
        ET0 = 1; //打开定时器0中断	
    
    //先初始化数码管,除了第3、6位为‘-’,其余均为0
    changeAll(0);
    setline(3);
    setline(6);
    }
    

    4.9 主函数

    void main()
    {
     init();
     while(1)
       {
          timeSignalHandler();
          displayLed();
          showTube();
          key1Action();
      }
    }
    

    5.技巧:这个属于精准时间计数。如何得出定时器初始值设置呢?
    STC-ISP的定时器计算器

    展开全文
  • STC单片机按键扫描程序演示

    千次阅读 2012-02-26 00:31:02
    编者寄语:此小演示程序仅用于演示按键扫描程序的设计。单片机为STC12C5A60S2,晶振频率为11.0592M。单片机P口上接8个LED灯。在按下按钮后分别点亮几个LED灯用于模拟其各自任务。按键采用查询方式。按键防抖动时间为...



    /*
     *AVR scan Keybord demo
     *------------------------
     *DESIGNED:yingxian_Fei
     *2012-2-25
     *This demo code use for show the action after someone pressed the keybord.
     *The program show the action to user by light LED.
     */
    #include <reg51.h>
    #include <intrins.h>
    #include <stdio.h>
    #include <stdlib.h>


    #define POUT P0   //设置输出的P口
    #define MASK 0xff
    #define LEDCON 0x03




    sfr AUXR   = 0x8E;


    sbit KEY1 = P2^0;
    sbit KEY2 = P2^1;
    sbit KEY3 = P2^2;
    sbit KEY4 = P2^3;


    void AppCall(void);
    void Task1(void);
    void Task2(void);
    void Task3(void);
    void Task4(void);
    void InitMCU(void);
    void InitTimer0(void);
    void KeyBord(void);
    void Delay_ms(unsigned char ms);


    unsigned char S1,S2,S3,S4;


    int main(void)
    {
       InitMCU();
       while(1)  {
          AppCall();
       }
       return 0;
    }


    void AppCall(void)
    {
       if(S1 == 1&&S2 != 1&&S3 != 1&&S4 != 1)  {
          Task1();
       }
       if(S2 == 1&&S1 != 1&&S3 != 1&&S4 != 1)  {
          Task2();
       }
       if(S3 == 1&&S2 != 1&&S1 != 1&&S4 != 1)  {
          Task3();
       }
       if(S4 == 1&&S2 != 1&&S3 != 1&&S1 != 1)  {
          Task4();
       }
    }


    void Task1(void)
    {
       unsigned char temp;
       POUT = MASK; 
       temp = _crol_(LEDCON,0);
       POUT = ~temp;
    }




    void Task2(void)
    {
       unsigned char temp;
       POUT = MASK; 
       temp = _crol_(LEDCON,2);
       POUT = ~temp;
    }


     
    void Task3(void)
    {
       unsigned char temp;
       POUT = MASK; 
       temp = _crol_(LEDCON,4);
       POUT = ~temp;
    }


     
    void Task4(void)
    {
       unsigned char temp;
       temp = _crol_(LEDCON,6);
       POUT = ~temp;
    }


    void InitMCU(void)
    {
        AUXR = AUXR|0x80;  // T0, 1T Mode
        InitTimer0();   
    }


    void InitTimer0(void)
    {
        TMOD = 0x01;
        TH0 = 0x0F7; //200us
        TL0 = 0x5C;
        EA = 1;
        ET0 = 1;
        TR0 = 1;
    }


    void Timer0Interrupt(void) interrupt 1
    {
        TF0 = 0;
    TH0 = 0x0F7;
        TL0 = 0x5C;
        KeyBord();
    TR0 = 1;
    }


    void KeyBord(void)
    {
       if(KEY1 == 0)  {
          Delay_ms(1);
     if(KEY1 == 0)  {
        S1 = 1;
    S2 = S3 = S4 = 0;
     }
       }
       if(KEY2 == 0)  {
          Delay_ms(1);
     if(KEY2 == 0)  {
        S1 = S3 = S4 = 0;
    S2 = 1;
     }
       }
       if(KEY3 == 0)  {
          Delay_ms(1);
     if(KEY3 == 0)  {
        S1 = S2 = S4 = 0;
    S3 = 1;
     }
       }
       if(KEY4 == 0)  {
          Delay_ms(1);
     if(KEY4 == 0)  {
        S1 = S2 = S3 = 0;
    S4 = 1;
     }
       }
    }


    void Delay_ms(unsigned char ms)
    {
       unsigned char a,b;
       while(ms--)  {
         for(b=18;b>0;b--)  {
            for(a=152;a>0;a--);
                _nop_();
    }
       }
    }




    编者寄语:此小演示程序仅用于演示按键扫描程序的设计。单片机为STC12C5A60S2,晶振频率为11.0592M。单片机P口上接8个LED灯。在按下按钮后分别点亮几个LED灯用于模拟其各自任务。按键采用查询方式。按键防抖动时间为1ms。使用时可通过宏定义PCONFIG设置输出所用的P口,如果不设置则采用默认输出P0口做为信号输出。闲暇至于写下此小程序仅供娱乐,大家多多指教。

    展开全文
  • 好久没写博客了,在经过一个学期的51单片机的学习,最终经过考核,终于进入了学校的基地,看到基地里面的机器人,那个兴奋啊。还记得当天8个小时的密闭环境的编程,没有胃口吃饭,没有心思吃饭,一直想着怎么完成...

    写在前面
    好久没写博客了,在经过一个学期的51单片机的学习,最终经过考核,终于进入了学校的基地,看到基地里面的机器人,那个兴奋啊。还记得当天8个小时的密闭环境的编程,没有胃口吃饭,没有心思吃饭,一直想着怎么完成题目,考完之后心里更忐忑,担心无法被录取,在收到面试消息之后,这个晚上,我应该一辈子都不会忘记,睡不着觉,失眠到1点半,早上5点半就醒了,当自己最终收到被录取的信息的时候,忐忑的心终于放下了。
    在进入基地之后开始学习STM32F1,继续写博客,记录下自己新的起点,新的路程。望自己也能在总结自己中提升,也希望在总结了每周之后,能给大家一个参考的作用。
    第一周学习任务作业
    1.用两个定时器,完成两个不同频率的呼吸灯。用四个按键分别进行频率增减
    学习感想
    接触到32的第一个感想就是复杂,天哪,真的是太复杂了,光是寄存器就有上百个,定时器就有11个,相比较而言,51单片机(89C52)里面的定时器顶天了,加上那个不太好配置的一共才3个,寄存器也远远不及32的寄存器,可以说32真的是太强大了,而学习了之后,发现里面需要配置的地方,配置的步骤,配置的函数,真的是挺多的。个人觉得,不能只学函数,还要学习配置寄存器,也是为了以后配置底层代码更加的方便。
    在这里插入图片描述

    任务实现思路
    任务的要求就是输出一个改变占空比的PWM方波来实现灯泡的亮度变化,然后用按键来改变亮度变化的频率。相信大家都知道呼吸灯实现的频率,就是使用不同占空比的PWM波来实现不同的电压,从而实现了流过灯泡电流的大小,从而改变的灯泡的亮度。
    我在思考用按键来改变频率的时候,想到应该可以改变每次输出定时器中断输出方波的时间来实现,也可以用改变方波的占空比来实现,因为在之前使用51单片机呼吸灯的时候,曾经尝试过改变定时器中断的方式来改变方波,但是发现效果并不是那么的好,同时衍生到STM32,效果应该也是不好的,思考里面的原因,个人人为,是两个定时器,如果设置相同的打断优先级,那么极有可能会造成一个中断要在另一个中断完成的时候,才能够中断完成,而这种情况,就会导致一个灯泡很有可能会卡顿,甚至出现一段时间的熄灭,所以就采用不同的占空比来进行输出,两个定时器中断的时间间隔是相同的,每次间隔的时间也是相同的,只会改变一段时间内的占空比,从而实现不同频率亮度的变化。而实现呼吸灯,是需要占空比增大和减小的,所以我们只需要改变占空比增大的最大值和减小到的最小值,就实现了呼吸灯的不同频率。
    下面主要部分实现的思路:
    配置两个定时器,设置中断时间,扫描按键,判断是否需要增加占空比,或者减少占空比,输出PWM方波。
    正点原子的开发板上面一个LED灯接的是PB5,一个接的是PE5,根据我们查开发手册可以得到的内容可以产生那个PWM方波的定时只有定时器2,3,4,5,所以我们就需要根据这四个定时器引出的引脚或者是重映射的IO口来进行配置,再进行查表得到,这4个定时器里面可以重映射出来的引脚就只有PB5,所以我们先配置好第一个IO口,并让其重映射到PB5上,让这一个IO口先输出PWM方波,这样就可以实现呼吸灯,因为另一个IO口不能直接配置IO口,所以我们需要人为的输出PWM方波,所以需要另外配置一个定时一定时间的定时器,并设置一个参数,在小于这一个参数的时候输出低电平,在大于这一个参数的时候输出高电平,这样就实现了PWM方波的输出。
    在这里插入图片描述

    主函数
    设置NVIC中断分组
    初始化各类需要使用的函数
    设置两个定时器中断频率
    按键扫描 实现最大占空比的增减
    自增自减方波控制
    方波中断函数
    输出方波

    注:代码是正点原子的代码进行改编而来,各个模块的代码大家可以去关注正点原子的微信来得到,都是开源的

    #include "led.h"
    #include "delay.h"
    #include "key.h"
    #include "sys.h"
    //#include "usart.h"
    #include "timer.h"
    
    u16 led1pwmval=0,led1pwmmax = 25;//val是当前输出的占空比,max最大的占空比
    
    //定时器4中断服务程序
    void TIM4_IRQHandler(void)   //TIM4中断
    {
    	static u16 nowtime = 0;			//记录当前的时间
    	extern u16	led1pwmmax;
    	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
    		{
    			TIM_ClearITPendingBit(TIM4, TIM_IT_Update);  //清除TIMx的中断待处理位:TIM 中断源 
    			nowtime++;
    			if(nowtime == 40)													//记录40次,也就是0.4ms一个周期,在这一个周期里面来输出方波
    				nowtime =  0;
    			if(nowtime <= led1pwmval)										//如果还没达到最高占空比,输出高电平
    				LED1 = 1;
    			else LED1 = 0;															//否则输出低电平
    		}
    }	
     int main(void)
     {		
     	u16 led0pwmval = 0,led0pwmmax = 25;							//led0的pwm值和pwm最大值
    	u8 dir = 1,dir1 = 1;														//用来判断两个方波占空比是增大还是减小
    	vu8 key = 0;
    	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级	
    	delay_init();	    	 		//延时函数初始化	  
    	//uart_init(115200);			//串口初始化为115200
    	LED_Init();			    		//LED端口初始化
    	KEY_Init();          	 	//初始化与按键连接的硬件接口
     	TIM3_PWM_Init(899,0);		//不分频。PWM频率=72000000/900=80Khz,不分频时钟频率就是72M
    	TIM4_Int_Init(1,719);//10Khz的计数频率,计数到1为0.01ms,0.01ms中断一次,这样显示从出来的方波才稳定
       	while(1)
    	{
     		delay_ms(10);	 				//延时灯亮度
    		
    		key=KEY_Scan(0);	//得到键值
    	   	if(key)
    		{						   
    			switch(key)
    			{				 
    				case WKUP_PRES:
    					led0pwmmax++;//增加占空比
    					break;
    				case KEY1_PRES:
    					led0pwmmax--;//减少占空比
    					break;
    				case KEY2_PRES:	//	 
    					led1pwmmax++;
    					break;
    				case KEY0_PRES:	//
    					led1pwmmax--;
    					break;
    			}
    		}
    		if(dir)led0pwmval++;	
    		else led0pwmval--;			
    		//当占空比大于50的时候,开始减少,从而实现从最亮变到最暗
    		//当我们只要使得输出最大的占空比增大或者减少的时候,就可以实现不同的频率
     		if(led0pwmval>led0pwmmax)dir=0;
    		if(led0pwmval==0)dir=1;										 
    		TIM_SetCompare2(TIM3,led0pwmval);
    		
    		
    		//和前面的方法是类似的,让占空比不断增加,然后不断减小,从而实现呼吸灯的效果
    		if(dir1)led1pwmval++;
    		else led1pwmval--;	   
    		if(led1pwmval>led1pwmmax)dir1=0;
    		if(led1pwmval<=0)dir1=1;	
    	}	 
     }
    
    
    
    #include "timer.h"
    #include "led.h"
    //#include "usart.h"
    							  
       	  
    //通用定时器3中断初始化
    //这里时钟选择为APB1的2倍,而APB1为36M
    //arr:自动重装值。
    //psc:时钟预分频数
    //这里使用的是定时器3!
    void TIM3_Int_Init(u16 arr,u16 psc)
    {
      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
    
    	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
    	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
     
    	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
    
    	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    
    	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
    							 
    }
    //定时器3中断服务程序
    void TIM3_IRQHandler(void)   //TIM3中断
    {
    	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
    		{
    		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 
    		LED1=!LED1;
    		}
    }
    /*以上函数都没有调用*/
    
    //TIM3 PWM部分初始化 
    //PWM输出初始化
    //arr:自动重装值
    //psc:时钟预分频数
    void TIM3_PWM_Init(u16 arr,u16 psc)
    {  
    	//需要配置的初始化变量
    	GPIO_InitTypeDef GPIO_InitStructure;
    	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	TIM_OCInitTypeDef  TIM_OCInitStructure;
    	
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);	//使能定时器3时钟
     	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟
    	
    	GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //Timer3部分重映射  TIM3_CH2->PB5    
     
       //设置该引脚为复用输出功能,输出TIM3 CH2的PWM脉冲波形	GPIOB.5
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO
     
       //初始化TIM3
    	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 
    	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    	
    	//初始化TIM3 Channel2 PWM模式	 
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
     	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
    	TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2
    
    	TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器
     
    	TIM_Cmd(TIM3, ENABLE);  //使能TIM3
    	
    
    }
    
    /*使能TIM4定时器,用来输出方波*/
    void TIM4_Int_Init(u16 arr,u16 psc)
    {
      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能
    
    	TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	 计数到5000为500ms
    	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
    	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
     
    	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新中断
    
    	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;  //TIM4中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    	NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
    
    	TIM_Cmd(TIM4, ENABLE);  //使能TIMx外设
    							 
    }
    
    
    #include "led.h"
    
    //初始化PB5和PE5为输出口.并使能这两个口的时钟		    
    //LED IO初始化
    void LED_Init(void)
    {
     
     GPIO_InitTypeDef  GPIO_InitStructure;
     	
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);	 //使能PB,PE端口时钟
    	
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				 //LED0-->PB.5 端口配置
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
     GPIO_Init(GPIOB, &GPIO_InitStructure);					 //根据设定参数初始化GPIOB.5
     GPIO_SetBits(GPIOB,GPIO_Pin_5);						 //PB.5 输出高
    
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	    		 //LED1-->PE.5 端口配置, 推挽输出
     GPIO_Init(GPIOE, &GPIO_InitStructure);	  				 //推挽输出 ,IO口速度为50MHz
     GPIO_SetBits(GPIOE,GPIO_Pin_5); 						 //PE.5 输出高 
    }
     
    
    
    展开全文
  • 一,按键控制数码管 ...//功能:任意独立按键控制(带扫描式的) //优点:中间有20ms延时函数消抖;可以扩展任意个按键;可移植 // 含扫描按键所有操作; //作者: 梦 //提醒: 记得点赞哦!!!!! //转载要著...
  • 基于51单片机的数字频率

    千次阅读 多人点赞 2020-02-04 23:15:00
    51单片机采样周期是2个机器周期,所以理论上测量的频率范围是1-500KHz。实际应用时,发现被测频率值越大那么测得频率的误差也越大。 误差原因分析: 1.定时器工作于方式1时在中断服务程序中需要重新给定时器赋装载值...
  • 描述基于单片机简易数字频率计设计方案(一)系统框图如图1所示,主要由AT89C52单片机、异或器件、LCD1602、电源等组成。测量频率的原理定时/计数器工作在方式1,每产生一次定时器0中断,计数65536个脉冲,此时的脉冲...
  • AVR单片机扫描键盘并且读入用户设定的频率值。随后,AVR单片机计算出AD9850的控制字,并且对AD9850发出指令。本文介绍的频率控制器可以通过“+1Hz”键和“–1Hz”键微调频率值。本文对频率控制器扩展了液晶显示模块...
  • 这篇博文主要记录51单片机键盘篇(非编码键盘与编码键盘、非编码键盘扫描方式、独立键盘、矩阵键盘键盘消抖等)包含原理图、代码等(一)基础补充1.键盘的任务2.键盘的识别3.如何消除按键的抖动4.非编码键盘与...
  • 1.实验任务如图4.13.1所示,P0端口接动态数码管的字形码笔段,P2端口接动态数码管的数...把“单片机系统”区域中的P0.0/AD0-P0.7/AD7用8芯排线连接到“动态数码显示”区域中的a-h端口上;(2).把“单片机系统”区...
  • 51单片机开发系列五_矩阵按键扫描

    千次阅读 2014-04-14 19:28:00
    矩阵按键扫描 象棋小子 1048272975 在嵌入式系统中,用的最多的输入设备就是按键,用户的应用需求可通过相应按键传递到系统软件中,软件转而完成用户请求,实现简单的人机交互。笔者此处就矩阵按键的实现作一个简单...
  • 这个是电路原理图*************************************************************入门级频率计设计*********************************精度低,希望各位初学者在此基础上修改为精度更高的程序*************本程序...
  • (2)下载后观察现象为:8个数码管从00-00-00开始计数,最右边二极管被点亮(默认为最高扫描频率所以秒部分变化很快) (3)辅助操作:长按下key1数码管扫描频率减半,从右起第二个二极管点亮、第一个灭,上方数码管...
  • 循环扫描键盘  ACALL KEY_CHECK  JNB KEYCARD,DISPLAY  INC KEYCOU DISPLAY: ;显示程序  MOV A,KEYCOU ;选显示第一位高位  DA A  ANL A,#0xF0 ;获得高四位  SWAP A ;将A的高四位和低四位对调  ...
  • AVR单片机扫描键盘并且读入用户设定的频率值。随后,AVR单片机计算出AD9850的控制字,并且对AD9850发出指令。本文介绍的频率控制器可以通过“+1Hz”键和“–1Hz”键微调频率值。本文对频率控制器扩展了液晶显示模块...
  • 《基于单片机的简易数字频率计设计报告.doc》由会员分享,可免费在线阅读全文,更多与《基于单片机的简易数字频率计设计报告(最终版)》相关文档资源请在帮帮文库(www.woc88.com)数亿文档库存里搜索。1、当GATE为高电...
  • 写在前面 单片机的定时器和中断可以说是贯穿了各个模块的始终,这一个概念可以说是最最最...当人不去触碰按键的时候,按键会有可能因为各种原因产生抖动,从到使得串口读取到的电压会在0/1之间来回跳动,这也就使得程
  • 系统的整体思路:主程序在初始化变量和寄存器之后,扫描按键,根据按键的情况执行相应的功能,然后在数码显示频率的值,显示完成
  • 按键扫描

    千次阅读 2012-11-14 15:15:23
    按键作为人类向单片机传递指令的载体,在单片机控制系统中,占有重要的地位,按键失灵,如同人失聪一样不听使唤,使控制系统陷入失控状态。按结构原理来分,按键有机械按键、薄膜按键、电容式触摸按键和电阻式触摸...
  • 本文是笔者在学习51单片机的笔记心得。这篇着重介绍C51单片机是如何检测独立按键以及矩阵键盘操作。
  • 在MCS-51单片机片内有一个高增益的反相放大器,反相放大器的输入端为XTAL1,输出端为XTAL2,由该放大器构成的振荡电路和时钟电路一起构成了单片机的时钟方式。电子学习资料大礼包​mp.weixin.qq.com在MCS-51单片机片...
  • 基于STM32f103ZET6单片机按键控制电机正反转(带PWM调速) 学了快半个月的STM32,收获颇多,很明显的感觉是32位的单片机要比8位单片机(51单片机)强的太多了,不管是性能还是功耗上和51是没法比的,而且还有许多的...
  • 单片机实现数字频率计 系统功能及指标 测量频率范围:10Hz~600kHz 测量精度:1%以内 系统设计方案及基本流程 unsigned char DispBuf[8]; 显示缓冲区,分别对应8个数码管每个数码管应该显示的数字 主要函数及其功能...
  • 接上一篇博客: ...单片机中断方案代码 #include <reg51.h> #include <absacc.h> #include <ctype.h> sbit KEY2 = P2^0; //按键1 high mode sbit KEY3 = P2^1; //按键2 low m
  • 基于单片机的条形码扫描系统设计

    千次阅读 2018-11-21 23:34:18
    按键电路设计 在由单片机组成的便携式商品条形码识别器,最实用的独立式键盘。这种键盘具有硬件与软件相对简单的特点,其缺点是按键数量较多时,要占用大量口线。独立按键电路设计如图所示。 时钟电路设计 单片机的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,700
精华内容 680
关键字:

单片机按键扫描频率