历史上的今天
返回首页

历史上的今天

今天是:2025年08月04日(星期一)

正在发生

2018年08月04日 | STM32 PCB触摸按键(RC检测法)

2018-08-04 来源:eefocus

无意中翻出了大学刚毕业时用来来忽悠老板的触摸按键的程序,突然感概白发又多了。做硬件的不容易,做软件的也不容易,做硬件又做软件的更不容易。。。。

回想起来印象也不深刻,感觉纯粹为了好玩,又发现了键盘边有个有三个焊盘的pcb板,心血来潮把就它翻新了一下。

感觉触摸按键比物理按键简单多了,物理按键还要按键(废话),但是触摸按键的可是是一个铜片,铁片,金属片(反正是导体就行了)。如果手头上又没有pcb按钮的,可以自己随便找个废板,在有铜片的地方挖个按钮引条线出来也是可以的,甚至拿一条导线也可以。手按按钮时要在按键上贴个胶纸绝缘,不然,按下的时候电流都被人体吸光了。


要说明一下,程序和硬件都是借鉴STM8,ST有相关例程,是AN几就忘了。st的例程使用的查询电平的方式,而且连充放电的时间也要去等,我用可是高贵的stm32这么宝贵的cpu时间岂能白白浪费掉,所以我就把它改成了中断触发的方式。

好了,先贴个原理图。


原理图就这么的简单。

PA4,是充电引脚。PA5、PA6、PA7是电平的检测引脚。这里用的是三个按键,R12、R13、R14是充电的限流电阻,这三个电阻要在几百K到几M欧之间,视单片机的性能而定吧,电阻越小电流越大充放电时间就越短,有句话说就是可以避免夜长梦多。但是电阻太小了,时间太短单片机就检测不到了。我在这选的是1M欧,充放电时间大概是10us,R15,R16,R17作用不是太大,不能取太大就是了。

所谓的RC法,就是R和C,R就是电阻,C就是电容也就是按键,利用充放电的时间来检测电容的变化。

更多的资料,百度谷歌很多,就不抛砖头了。

我的按键是这样的,注意要贴上胶布绝缘。


好了贴程序


这里是三个按键,硬件资源使用了两个定时器,4个IO口

TIM2用于时间的记录。

TIM3每100us触发一次,Ttimer_cnt 记录的是触发次数

Ttimer_cnt  = 1 现在所有IO都为低电平状态配置所有IO为输入高电平触发中断,并拉高充电的IO口

Ttimer_cnt  = 4到这时所有的IO已经充电完毕,可以记录充电的时间

Ttimer_cnt  = 5现在的所有IO口都处于高电平状态,配置所有IO为输入低电平触发中断,并拉低充电的IO口,放电

Ttimer_cnt  = 8到这时,所有的IO都放电完毕,记录放电时间

Ttimer_cnt  = 9计算按键的充放电时间值,滤波。Ttimer_cnt  = 0;


芯片使用的是stm32F103


//.h文件

typedef struct 

{

uint32_t Pin;//引脚

uint32_t staus;

uint32_t even;

uint32_t Realse;

uint32_t check_cnt;

uint32_t MeasRejected;

uint32_t RejectionCounter;

uint32_t Up_Cnt;

uint32_t Down_Cnt;

    uint32_t Temp_Cnt;

uint32_t AcqLoopIndex;

uint32_t Shifter;

uint32_t MaxMeasurement;

uint32_t MinMeasurement;

uint32_t Measurement;

uint32_t FinalMeasurementValue;

uint32_t CumulatedMeasurement;

uint32_t ReadMeasurement;//检测结果

uint32_t Eline;

}Tkey_Action;

//.c文件

 

 

#define KEYNUMS 3

//IO方向设置

//    IO口设置76543210       IO口设置76543210

#define ACQ_IN(x)  {GPIOA->CRL&= ~(0xF << (uint32_t)(x));GPIOA->CRL|= (0x4 << (uint32_t)(x));} //配置为输入高阻

#define ACQ_OUT(x) {GPIOA->CRL&= ~(0xF << (uint32_t)(x));GPIOA->CRL|= (0x8 << (uint32_t)(x));} //配置为推挽输出

//IO口操作

#define OUT_OUT PAout(4) //充放电引脚

#define SAMPLING_SHIFTER_LOOP_START (1)

#define SAMPLING_SHIFTER_NB_LOOPS (8)

 

 

 

 

#define MAX_MEAS_COEFF (0x150) //检测结果误差最大值自己调一个合适的值 > 255

#define MIN_MEAS_COEFF (0xBC)//检测结果误差允许最小值自己调一个合适的值 < 255

 

 

#define MAX_REJECTED_MEASUREMENTS (5)

 

 

Tkey_Action Tkey[KEYNUMS];

uint32_t Tkey_cnt;

uint32_t Ttimer_cnt;

uint32_t Cnt_Dat;

//extern unsigned int cnt;

 

void Tkey_Init(void);

 

void TkeyTestFunc(void){//

Tkey_Init();

while(1){

//delay_ms(250);

//printf("Get KEY0 %d,KEY1 %d,KEY2 %d\r\n",Tkey[0].ReadMeasurement,Tkey[1].ReadMeasurement,Tkey[2].ReadMeasurement);

if(Tkey[0].ReadMeasurement > 1700)//测量值,跟实际pcb按键电容的大小有关

{

if(Tkey[0].Realse  == 0){

printf("KEY0 Press\r\n");

}

Tkey[0].Realse = 1;//按键按下

}else{

if(Tkey[0].Realse  == 1){

printf("KEY0 Realse\r\n");

}

Tkey[0].Realse = 0;//按键释放

}

if(Tkey[1].ReadMeasurement > 2300)//测量值,跟实际pcb按键电容的大小有关

{

if(Tkey[1].Realse  == 0){

printf("KEY1 Press\r\n");

}

Tkey[1].Realse = 1;

}else{

if(Tkey[1].Realse  == 1){

printf("KEY1 Realse\r\n");

}

Tkey[1].Realse = 0;

}

if(Tkey[2].ReadMeasurement > 2400)//测量值,跟实际pcb按键电容的大小有关

{

if(Tkey[2].Realse  == 0){

printf("KEY2 Press\r\n");

}

Tkey[2].Realse = 1;

}else{

if(Tkey[2].Realse  == 1){

printf("KEY2 Realse\r\n");

}

Tkey[2].Realse = 0;

}

 

}

}

 

 

void Tkey_Exti_Init(void)//按键的外部中断检测

{

GPIO_InitTypeDef GPIO_InitStructure;

EXTI_InitTypeDef EXTI_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure; 

 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);    //复用时钟

 

 

 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitStructure); 

 

 

 

 

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_Pin_5);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_Pin_6);

    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_Pin_7);

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //设置为中断请求

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //设置中断触发方式为下降沿触发

EXTI_InitStructure.EXTI_LineCmd = ENABLE;                                          //外部中断使能

    

    EXTI_InitStructure.EXTI_Line = EXTI_Line5; //选择中断线路1

EXTI_Init(&EXTI_InitStructure);

    EXTI_InitStructure.EXTI_Line = EXTI_Line6; //选择中断线路1

EXTI_Init(&EXTI_InitStructure);

    EXTI_InitStructure.EXTI_Line = EXTI_Line7; //选择中断线路1

EXTI_Init(&EXTI_InitStructure);

 

 

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;

NVIC_Init(&NVIC_InitStructure);

 

 

 

}

void Tkey_Timer_Init(void)//相关定时器初始化

{

TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

/* TIM2 and TIM3 clocks enable */

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE);

/* 1 bit for pre-emption priority, 3 bits for subpriority */

NVIC_SetPriorityGrouping(6); 

NVIC_DisableIRQ(TIM2_IRQn);

/* TIM2 configuration -------------------------------------------------------*/

TIM_DeInit(TIM2);

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

TIM_TimeBaseStructure.TIM_Prescaler = 0x01;    /* TIM2CLK = 72 MHz */

TIM_TimeBaseStructure.TIM_Period = 0xFFFF;

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

//TIM_GetCounter(TIM2);

    TIM2->ARR = 0xFFFF;

  

  /* Enable the TIM Counter */

    TIM2->CR1 |= ((uint16_t)0x0001);

 

 

  /* Clear the IT pending Bit */

    TIM2->SR = ((uint16_t)(~TIM_IT_Update));

 

 

  /* Enable TIM2 update interrupt */

 

 

  

/* Enable the TIM3 Interrupt */

NVIC_SetPriority(TIM3_IRQn, 0x01); /* 0x00 = 0x01 << 3 | (0x00 & 0x7*/

NVIC_EnableIRQ(TIM3_IRQn);

 

 

 

/* TIM3 configuration -------------------------------------------------------*/

TIM_DeInit(TIM3);

/* TIM3 used for timing, the timing period depends on the sample rate */

TIM_TimeBaseStructure.TIM_Prescaler = 0x00;    /* TIM2CLK = 72 MHz */

TIM_TimeBaseStructure.TIM_Period = 7199; //0.10ms

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

//TIM_GetCounter(TIM2);

 /* Relaod ARR register */

    TIM3->ARR = 7199;

  

  /* Enable the TIM Counter */

    TIM3->CR1 |= ((uint16_t)0x0001);

 

 

  /* Clear the IT pending Bit */

    TIM3->SR = ((uint16_t)(~TIM_IT_Update));

   TIM3->DIER |= ((1 << 6) | (1 << 0));

 

 

 

 

}

 

 

void Tkey_ParInit(Tkey_Action *Tkey_Std,uint32_t GPIOnums){//按键数据结构初始化

    Tkey_Std->Shifter = 1;

Tkey_Std->AcqLoopIndex = 0;

Tkey_Std->MeasRejected = 0;

Tkey_Std->RejectionCounter = 0;

Tkey_Std->staus = 0;

Tkey_Std->Pin = GPIOnums;//引脚

Tkey_Std->Eline = (uint32_t)(1 << GPIOnums);//中断资源

}

 

 

void Tkey_Init(void)

{

    uint32_t i;

GPIO_InitTypeDef Tkey_Struct;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

Tkey_Struct.GPIO_Pin = (GPIO_Pin_4);//充放电IO

Tkey_Struct.GPIO_Speed = GPIO_Speed_50MHz;

Tkey_Struct.GPIO_Mode = GPIO_Mode_Out_PP; 

GPIO_Init(GPIOA,&Tkey_Struct);

GPIO_ResetBits(GPIOA,GPIO_Pin_4);

 

 

    for(i=0;i

        Tkey_ParInit(&Tkey[i],i+5);//初始化按键数据参数,按键端口为GPIO5/6/7

    }

    Tkey_Exti_Init();//设置硬件参数

    Tkey_Timer_Init();//启动动定时器

Tkey_cnt = 0;

 

}

 

__forceinline void Tkey_upCheck(void)

{

    uint32_t i;

    uint32_t ExitLine = 0;

    

    for(i=0;i

        Tkey[i].Up_Cnt = Tkey[i].Temp_Cnt;////记录时间

        PAout(Tkey[i].Pin) = 1;//输出高电平,开始充电

        ACQ_OUT(Tkey[i].Pin);//设置为输出状态

        ExitLine |= Tkey[i].Eline;

    }

    EXTI->IMR &= ~(ExitLine);//失能中断

 

}

__forceinline void Tkey_Vih(Tkey_Action *Tkey_Std)//等待到达上升沿设置

{

ACQ_IN(Tkey_Std->Pin);//按键检测端口设置为输入高阻态

EXTI->FTSR &= ~(Tkey_Std->Eline);

EXTI->RTSR |= (Tkey_Std->Eline);//设置为上升沿触发

EXTI->IMR |= (Tkey_Std->Eline);//使能中断

 

}

 

 

__forceinline void Tkey_downCheck(void)//记录放电时间

{

    uint32_t i;

    uint32_t ExitLine = 0;

    

    for(i=0;i

        Tkey[i].Up_Cnt = Tkey[i].Temp_Cnt;////记录时间

        PAout(Tkey[i].Pin) = 0;//输出低电平,放电

        ACQ_OUT(Tkey[i].Pin);//输出低电平,放电

        ExitLine |= Tkey[i].Eline;

    }   

    EXTI->IMR &= ~(ExitLine);//失能中断

 

}

__forceinline void Tkey_Vil(Tkey_Action *Tkey_Std)//等待到达下降沿设置

{

 

 

ACQ_IN(Tkey_Std->Pin);//配置为高阻态,等待放电完成

EXTI->FTSR |= (Tkey_Std->Eline);

EXTI->RTSR &= ~(Tkey_Std->Eline);//设置为下降沿触发

EXTI->IMR |= (Tkey_Std->Eline);//使能中断

}

__forceinline void Tkey_Vil_All(void)

{

    uint32_t i;

    uint32_t ExitLine = 0;

    for(i=0;i

        ExitLine |= Tkey[i].Eline;

    }

    for(i=0;i

        ACQ_IN(Tkey[i].Pin);//所有检测端口配置为输入

    }

EXTI->FTSR |= (ExitLine);

EXTI->RTSR &= ~(ExitLine);//所有检测端口设置为下降沿触发

EXTI->IMR |= (ExitLine);//使能中断

    

}

__forceinline void Tkey_Vih_All(void)

{

uint32_t i;

    uint32_t ExitLine = 0;

    for(i=0;i

        ExitLine |= Tkey[i].Eline;

    }

    for(i=0;i

        ACQ_IN(Tkey[i].Pin);//所有检测端口配置为输入

    }

    

    EXTI->FTSR &= ~(ExitLine);

EXTI->RTSR |= (ExitLine);//所有检测端口设置为上升沿触发

EXTI->IMR |= (ExitLine);//使能中断

    

}

void Tkey_TDeal(Tkey_Action *Tkey_Std)

{

unsigned int temp;

Tkey_Std->Measurement = (Tkey_Std->Up_Cnt + Tkey_Std->Down_Cnt);//充放电的总时间

Tkey_Std->CumulatedMeasurement += Tkey_Std->Measurement;//统计时间值

if(Tkey_Std->Shifter == 1)//第一次检测,计算出参考值

{

temp = Tkey_Std->Measurement * MAX_MEAS_COEFF;

Tkey_Std->MaxMeasurement = (temp >> 8) + 8;

temp = Tkey_Std->Measurement * MIN_MEAS_COEFF;

Tkey_Std->MinMeasurement = (temp >> 8) + 8;

 

}

else//非第一次检测判断值是否在范围内

{

if ((Tkey_Std->Measurement < Tkey_Std->MinMeasurement) || (Tkey_Std->Measurement > Tkey_Std->MaxMeasurement))//超出可接收范围

{

Tkey_Std->MeasRejected++;

Tkey_Std->RejectionCounter++;

Tkey_Std->Shifter = 8;//

//break; // Out from 'for SamplingShifter' loop !!!

}

Tkey_Std->Shifter ++;//检测次数++

 

if(Tkey_Std->Shifter > 8)//检测达八次

{

if(Tkey_Std->MeasRejected && (Tkey_Std->RejectionCounter <= MAX_REJECTED_MEASUREMENTS))//非法的次数大于可接受范围

{

Tkey_Std->Shifter = 1;

}

else//重新开始

{

 

if (Tkey_Std->MeasRejected == 0)//

{

Tkey_Std->FinalMeasurementValue += Tkey_Std->CumulatedMeasurement;

Tkey_Std->Shifter = 1;

Tkey_Std->AcqLoopIndex ++;

}

else // RejectionCounter > MAX_REJECTED_MEASUREMENTS //

{

//break; // Out from 'for AcqLoopIndex' loop !!!

Tkey_Std->AcqLoopIndex = 3;

Tkey_Std->FinalMeasurementValue = 0;

}

}

Tkey_Std->MeasRejected = 0;

    Tkey_Std->CumulatedMeasurement = 0;

 

 

}

if(Tkey_Std->AcqLoopIndex > 2)//一轮的检测完成

{

if (Tkey_Std->RejectionCounter <= MAX_REJECTED_MEASUREMENTS)

{

Tkey_Std->ReadMeasurement = (Tkey_Std->FinalMeasurementValue >> 3); /* Division by SAMPLING_SHIFTER_NB_LOOPS */

}

else

Tkey_Std->ReadMeasurement = 0;//结果非法

Tkey_Std->AcqLoopIndex = 0;

Tkey_Std->MinMeasurement = 0;

   Tkey_Std->MaxMeasurement = 0;

   Tkey_Std->RejectionCounter = 0;

Tkey_Std->Shifter = 1;

Tkey_Std->staus = 1;

Tkey_Std->FinalMeasurementValue = 0;

}

}

 

 

void TIM2_IRQHandler(void)

{

    /* Relaod output compare */

    TIM2->ARR = 0xFFFF;

  

  /* Clear TIM2 update interrupt */

    TIM2->SR = ((uint16_t)(~TIM_IT_Update));

}

 

 

void TIM3_IRQHandler(void)

{

    /* Relaod output compare */

    TIM3->ARR = 7199;

if(Ttimer_cnt == 1)

{

/*

配置IO输入,上升沿触发,使能中断;

*/

Tkey_Vih_All();

TIM2->CNT = 0;//重置计数器

OUT_OUT = 1;//充电口输出高电平

}else if(Ttimer_cnt == 4)

{

/*

记录下CNT计数值;设置IO口输出模式,使电容屏充满电;

        到这个时候,理论上所有的端口都已经充满电并触发中断了

*/

        Tkey_upCheck();

 

}else if(Ttimer_cnt == 5)

{

/*

配置IO输入,下降沿触发,使能中断;

*/

Tkey_Vil_All();

        TIM2->CNT = 0;//重置计数器

OUT_OUT = 0;//充电口输出低电平

 

 

}else if(Ttimer_cnt == 8)

{

        

/*

记录下CNT计数值;设置IO口输出模式,使电容按键放光电;

*/

Tkey_downCheck();

        

        

}else if(Ttimer_cnt == 9)

    {

        unsigned int i;

        for(i=0;i

            Tkey_TDeal(&Tkey[i]);

        }

       Ttimer_cnt = 0;//一个周期的检测结束

    }

Ttimer_cnt ++;

  /* Clear TIM2 update interrupt */

    TIM3->SR = ((uint16_t)(~TIM_IT_Update));

}

__forceinline void Tkey_RecordTime(Tkey_Action *Tkey_Std){

    if(EXTI->PR  & (Tkey_Std->Eline))

{

EXTI->IMR &= ~(Tkey_Std->Eline);//失能中断

Tkey_Std->Temp_Cnt = TIM2->CNT;

EXTI->PR |= (Tkey_Std->Eline);

 

}

}

void EXTI9_5_IRQHandler(void)

{

/*

记录下中断触发时的计数器计数;

*/

uint32_t i;

    for(i=0;i

Tkey_RecordTime(&Tkey[i]);

}

 

}


推荐阅读

史海拾趣

台湾美丽微(FMS)公司的发展小趣事

FTDI的历史可以追溯到1992年3月13日,由弗雷德·达特(Fred Dart)创立。公司初期专注于个人电脑市场,推出了针对主板芯片组的解决方案。其中,早期的主要客户之一是IBM,这些芯片被应用于AMBRA和PS/2系列的个人电脑中,为当时的计算机技术发展做出了重要贡献。这一时期的成功不仅奠定了FTDI的技术基础,也为其后续的市场拓展奠定了坚实的客户基础。

圣邦微电子(Fangtek)公司的发展小趣事

近年来,FTDI通过战略并购进一步拓展了其业务领域。例如,电连技术通过发行股份及支付现金的方式收购了FTDI的控股权,这一举措不仅使电连技术在产品和客户层面实现了更完整的布局,也增强了其在汽车电子、物联网、工业产品、医疗设备等多个领域的市场竞争力。FTDI凭借其在USB桥接芯片领域的深厚积累和技术优势,为电连技术的业务扩展提供了有力支持,共同推动了公司在全球电子元件产业的持续发展。

上海晶丰明源(BPS)公司的发展小趣事

近年来,电子行业面临着诸多挑战,如市场竞争加剧、技术更新换代迅速等。然而,晶丰明源凭借强大的研发实力和敏锐的市场洞察力,成功应对了这些挑战。公司不仅加大了研发投入,加强了与高校、科研机构的合作,还积极引进和培养人才,为公司的发展注入了新的活力。同时,公司还注重产品创新和品牌建设,不断提升产品的附加值和竞争力。

AZM [Arizona Microtek, Inc]公司的发展小趣事

随着电子行业的快速发展,AZM公司意识到只有不断创新才能在激烈的市场竞争中立于不败之地。因此,公司加大了对研发的投入,积极引进高端人才,建立了完善的研发体系。通过持续的技术创新,AZM公司成功推出了一系列具有领先水平的微电子产品,不仅提升了公司的市场竞争力,也为整个电子行业的发展做出了贡献。

Excelsys公司的发展小趣事

人才是企业发展的核心驱动力。Excelsys公司高度重视人才培养和团队建设。公司建立了完善的人才培养机制,为员工提供系统的培训和学习机会;同时,公司还注重团队文化的建设,营造积极向上、团结协作的工作氛围。这些措施为公司的持续发展提供了有力的人才保障。

AIM公司的发展小趣事

AIM公司自创立以来,便以其前瞻性的视野和独特的技术理念,在电子行业中崭露头角。创始团队凭借对市场的敏锐洞察和对技术的深刻理解,将公司定位为提供创新解决方案的引领者。在创立初期,AIM便投入大量资源进行技术研发,逐渐在行业中建立了自己的技术优势和品牌形象。

问答坊 | AI 解惑

开关电源指标的定义

本帖最后由 paulhyde 于 2014-9-15 04:13 编辑 一.描述输入电压影响输出电压的几个指标形式。 1.绝对稳压系数。 A.绝对稳压系数:表示负载不变时,稳压电源输出直流变化量△U0与输入电网变化量△Ui之比。既: K=△U0/△Ui。 B. 相对稳压系 ...…

查看全部问答>

故障问题

[原创]一个查找电路和器件故障机理的好仪器好方法 最近帮助一些客户做电路故障的分析,在了解情况过程中,问起哪里坏了,大都能告诉我“某某器件坏了”,但再问“哪个管脚坏了”“可能是什么原因造成的”“坏到了啥程度”,往往就没人接茬了,即 ...…

查看全部问答>

请教关于电池的问题

大家有知道一次性电池中寿命最长的是那种吗?使用寿命。最大能做到多少mAH呢? 先谢谢了 补充:不知道一次性电池的寿命是不是也是用mAh来衡量呢,如果不是,要怎么判断呢? [ 本帖最后由 silencepiece 于 2010-6-4 16:52 编辑 ]…

查看全部问答>

在驱动程序中操作文件

谁有内核模式下读写文件的源代吗,我想在驱动中写入调试信息到Log文件。…

查看全部问答>

DS1302 GCC程序怎么结果又错

#include #include //寄存器宏定义 #define WRITE_SECOND              0x80 #define WRITE_MINUTE        0x82 #define WRITE_HOUR     &n ...…

查看全部问答>

AT89C2051芯片控制发光二极管

问下各位,一个AT89C2051芯片最多能够驱动多少个发光二极管? 对电压有怎样的要求,用5V的电压可以吗?…

查看全部问答>

求win ce 5.0下能用的usb接口蓝牙模块

如题 最好能详细介绍一下 谢谢…

查看全部问答>

如何使用OSAL的事件?

以前的帖子,重新整理到这个版面。   OSAL通过一个16位宽度的数组来管理事件,意味着OSAL最多可以支持16个事件,其中最高位(0x08000,SYS_EVENT_MSG)系统保留,用户可以使用的事件有15个。事件的使用很简单:1)需要找个地方定义事件的ID ...…

查看全部问答>

电压反馈型运放和电流反馈型运放的电流噪声的区别

求助各位高手: CFB的电流噪声分为同相端的和反相端的,VFB只给出一种电流噪声。那么在VFB噪声计算中,电流噪声只在同相端或反相端添加还是两端都添加,只不过值是相同的?十分感谢! [ 本帖最后由 mazzz 于 2011-11-17 23:36 编辑 ]…

查看全部问答>