完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
要点亮LED灯或获得输入IO的状态应该是比较容易的,打开端口时钟,然后读写相关的GPIO寄存器就可以了,但是要实现一个输入中断,就要费些周折了。 对STM32(Cortex-M3)的芯片,要实现一个GPIO中断一般需要如下几步: 1、 配置时钟控制器寄存器(RCC)的APB2RSTR,确保对应的GPIOA ~ GPIOG时钟使能。 2、 对GPIO寄存器的CRL(或CRH)要设置正确的输入模式,如浮空输入模式(对接收IO中断来说,当然要设置成输入模式)。 3、 要通过AFIO寄存器配置中断的输入来源,对STM32芯片来说,具有19路EXti中断线,其中3路分别连接PVD输出、RTC闹钟事件及USB唤醒事件,剩下的对GPIOA ~ GPIOG 7*16=112个IO点来说,同时只能配置16路IO输入中断。 4、 接下来要配置EXIT寄存器,根据需要来配置是上升沿触发中断、还是下降沿触发中断或两者都触发。 5、 而后比较重要的是, 要配置NVIC的SETENA寄存器,让对应的EXTI0、EXTI1、EXTI2、EXTI3、EXTI4、EXTI9_5或EXTI15_10中断位使能,此外还要配置各中断的优先级(前提是中断优先级分组寄存器已配置完毕)。 6、 最后我们要设置中断向量表(该向量表要重定位到内存中,以便于动态修改),在EXTI0、EXTI1、EXTI2、EXTI3、EXTI4、EXTI9_5或EXTI15_10对应的位置,放入我们的中断函数的入口地址。 和PC平台程序开发不同,基本上你每做一步,都可以很直观的看到你的进展和成果,但对嵌入式开发来说,如果上述几步有任何一个环节出了问题,你的进展都是零,有时候你会花上一天的时间去反复核实每个寄存器的值是否正确,以期获得你希望的结果。所以说嵌入式开发是惊喜的型的,要么成,要么不成,一线之隔! 接下来我们说一下GPIO实现的详细步骤,首先在CortexM3.h头文件中添加GPIO相关的寄存器描述: struct CortexM3_GPIO { static const UINT32 c_Base = 0x40010800; static const UINT32 A = 0; static const UINT32 B = 1; static const UINT32 C = 2; static const UINT32 D = 3; static const UINT32 E = 4; static const UINT32 F = 5; static const UINT32 G = 6; static const UINT32 GPIO_Mode_NULL = 0x00; static const UINT32 GPIO_Mode_Speed_10MHz = 0x01; static const UINT32 GPIO_Mode_Speed_2MHz = 0x02; static const UINT32 GPIO_Mode_Speed_50MHz = 0x03; static const UINT32 GPIO_Mode_IN_FLOATING = 0x04; /****/ volatile UINT32 CRL; //配置寄存器 /****/ volatile UINT32 CRH; /****/ volatile UINT32 IDR; //数据寄存器 /****/ volatile UINT32 ODR; /****/ volatile UINT32 BSRR; //置位复位寄存器 /****/ volatile UINT32 BRR; //复位寄存器 /****/ volatile UINT32 LCKR; //锁定寄存器 }; struct CortexM3_EXTI { static const UINT32 c_Base = 0x40010400; /****/ volatile UINT32 IMR; /****/ volatile UINT32 EMR; /****/ volatile UINT32 RTSR; /****/ volatile UINT32 FTSR; /****/ volatile UINT32 SWIER; /****/ volatile UINT32 PR; }; struct CortexM3_AFIO { static const UINT32 c_Base = 0x40010000; /****/ volatile UINT32 EVCR; /****/ volatile UINT32 MAPR; /****/ volatile UINT32 EXTICR[4]; }; 由于NVIC相关的代码我们已经在《NVIC中断处理》说过了,这里就不重复了。 对.Net Micro Framework的架构来说,要实现如下几个接口: 1、CPU_GPIO_Initialize 2、CPU_GPIO_Uninitialize 3、CPU_GPIO_Attributes 4、CPU_GPIO_DisablePin 5、CPU_GPIO_EnableOutputPin 6、CPU_GPIO_EnableInputPin 7、CPU_GPIO_EnableInputPin2 8、CPU_GPIO_GetPinState 9、CPU_GPIO_SetPinState 10、CPU_GPIO_GetPinCount 11、CPU_GPIO_GetPinsMap 12、CPU_GPIO_GetSupportedResistorModes 13、CPU_GPIO_GetSupportedInterruptModes 14、CPU_GPIO_PinIsBusy 15、CPU_GPIO_ReservePin 16、CPU_GPIO_GetDebounce 17、CPU_GPIO_SetDebounce 考虑到难易程度和篇幅,我们只介绍CPU_GPIO_Initialize、CPU_GPIO_EnableOutputPin、 CPU_GPIO_EnableInputPin和EXTI_IRQHandler 中断函数的具体实现。 BOOL GPIO_Driver::Initialize() { CortexM3_AFIO &AFIO = CortexM3::AFIO(); for(int i=0;i<4;i++) { AFIO.EXTICR=0x0000; } CortexM3_EXTI &EXTI= CortexM3::EXTI(); EXTI.IMR = 0x00000000; EXTI.EMR = 0x00000000; EXTI.RTSR = 0x00000000; EXTI.FTSR = 0x00000000; EXTI.PR = 0x0007FFFF; //NVIC if(!CPU_INTC_ActivateInterruptEx(CortexM3_NVIC::c_IRQ_Index_EXTI0,(UINT32)(void *)EXTI_IRQHandler )) return FALSE; //略 return TRUE; } 其中比较重要的是CPU_INTC_ActivateInterruptEx函数,它可动态设置c_IRQ_Index_EXTI0中断所对应的中断函数的入口地址。 void GPIO_Driver::EnableOutputPin(GPIO_PIN pin, BOOL initialState) { ASSERT(pin < c_MaxPins); UINT32 port = PinToPort(pin); UINT32 bit = PinToBit(pin); UINT32 pos = (bit % 8)<<2; CortexM3_GPIO &GPIO= CortexM3::GPIO(port); //通用推挽输出模式 if(bit<8) { GPIO.CRL = (GPIO.CRL & ~(0x0F << pos)) | (CortexM3_GPIO::GPIO_Mode_Speed_50MHz << pos); } else { GPIO.CRH = (GPIO.CRH & ~(0x0F << pos)) | (CortexM3_GPIO::GPIO_Mode_Speed_50MHz << pos); } //初值 if(initialState) GPIO.BSRR = 0x1 << bit; else GPIO.BRR = 0x1 << bit; } 输出默认为通用推挽输出模式,你也可以根据实际需要进行必要的调整。 BOOL GPIO_Driver::EnableInputPin(GPIO_PIN pin, BOOL GlitchFilterEnable, GPIO_INTERRUPT_SERVICE_ROUTINE ISR, void *pinIsrParam, GPIO_INT_EDGE intEdge, GPIO_RESISTOR resistorState) { ASSERT(pin < c_MaxPins); UINT32 port = PinToPort(pin); UINT32 bit = PinToBit(pin); UINT32 pos = (bit % 8)<<2; CortexM3_GPIO &GPIO= CortexM3::GPIO(port); //浮空输入 if(bit<8) { GPIO.CRL = (GPIO.CRL & ~(0x0F << pos))| (CortexM3_GPIO::GPIO_Mode_IN_FLOATING << pos); } else { GPIO.CRH = (GPIO.CRH & ~(0x0F << pos))| (CortexM3_GPIO::GPIO_Mode_IN_FLOATING << pos); } //中断输入源配置(AFIO) CortexM3_AFIO &AFIO = CortexM3::AFIO(); AFIO.EXTICR[bit >> 2] &= ~(0x0F << (0x04 * (bit & 0x03))); AFIO.EXTICR[bit >> 2] |= port << (0x04 * (bit & 0x03)); CortexM3_EXTI &EXTI=CortexM3::EXTI(); if(ISR) { switch(intEdge) { case GPIO_INT_NONE: //无中断 EXTI.IMR &= ~(0x1< return FALSE; case GPIO_INT_EDGE_LOW: //下降沿中断 case GPIO_INT_LEVEL_LOW: EXTI.IMR |= 0x1< EXTI.FTSR |= 0x1<
EXTI.RTSR &= ~(0x1<
break; //略 default: ASSERT(0); return FALSE; } } return TRUE; } GPIO输入的实现比较繁琐一些,可以根据需要仅把端口配置成输入模式,而不配置相应的中断参数。这样可以通过不断扫描的方式获得输入信号。 void GPIO_Driver::ISR(void *Param) { CortexM3_EXTI &EXTI=CortexM3::EXTI(); UINT32 interruptsActive = EXTI.PR; UINT32 bitMask = 0x1, bitIndex = 0; while(interruptsActive) { while((interruptsActive & bitMask) == 0) { bitMask <<= 1; ++bitIndex; } CortexM3_AFIO &AFIO = CortexM3::AFIO(); UINT32 port = (AFIO.EXTICR[bitIndex >> 2]>>(0x04 * (bitIndex & 0x03))) & 0xF; GPIO_PIN pin = BitToPin( bitIndex, port); PIN_ISR_DESCRIPTOR& pinIsr = g_GPIO_Driver.m_PinIsr[ pin ]; pinIsr.Fire( (void*)&pinIsr ); interruptsActive ^= bitMask; EXTI.PR |= bitMask; } } 在中断函数中,根据相关寄存器的值来判断哪一个(或同时哪一些)GPIO发生的中断,并由此执行业已配置好的异步中断处理函数。 好了,写完了GPIO驱动程序,我们就可以漂漂亮亮的在NativeSample中写我们的测试程序了: void ISR( GPIO_PIN Pin, BOOL PinState, void* Param ) { if(PinState) // released, up { CPU_GPIO_SetPinState(GPIO_Driver::PF7,0x0); } else // pressed, down { CPU_GPIO_SetPinState(GPIO_Driver::PF7,0x1); } } void ApplicationEntryPoint() { //LED D1 D2 D3 D4 CPU_GPIO_EnableOutputPin(GPIO_Driver::PF7,FALSE); CPU_GPIO_EnableOutputPin(GPIO_Driver::PF8,FALSE); //user按钮 = 0x1 CPU_GPIO_EnableInputPin(GPIO_Driver::PG8,FALSE,ISR,GPIO_INT_EDGE_BOTH,RESISTOR_PULLDOWN); while(TRUE) { CPU_GPIO_SetPinState(GPIO_Driver::PF8,!CPU_GPIO_GetPinState(GPIO_Driver::PF8)); Events_WaitForEvents( 0, 1000 ); } } |
|
相关推荐 |
|
你正在撰写讨论
如果你是对讨论或其他讨论精选点评或询问,请使用“评论”功能。
1107 浏览 0 评论
AD7686芯片不传输数据给STM32,但是手按住就会有数据。
1055 浏览 2 评论
2159 浏览 0 评论
如何解决MPU-9250与STM32通讯时,出现HAL_ERROR = 0x01U
1253 浏览 1 评论
hal库中i2c卡死在HAL_I2C_Master_Transmit
1678 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 07:47 , Processed in 1.987658 second(s), Total 42, Slave 33 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号