SmartOS之(C++)------输入输出端口类Port

 

 

  SmartOS (C++)的GPIO驱动,兼容STM32F0/F1/F4/GD32F10x/GD32F1x0

 

  头文件

  

  1 #ifndef _Port_H_

  2 #define _Port_H_

  3 

  4 #include "Sys.h"

  5 #include "ADC.h"

  6 

  7 #ifdef STM32F4

  8         #define GPIO_MAX_SPEED 100

  9 #else

 10         #define GPIO_MAX_SPEED 50

 11 #endif

 12 

 13 // 端口基类

 14 // 用于管理一个端口,通过PinBit标识该组的哪些引脚。

 15 // 子类初始化时先通过SetPort设置端口,备份引脚状态,然后Config通过gpio结构体配置端口,端口销毁时恢复引脚状态

 16 class Port

 17 {

 18 public:

 19     GPIO_TypeDef*        Group;                // 针脚组

 20     Pin                                _Pin;                // 针脚

 21     ushort                        PinBit;                // 组内引脚位。每个引脚一个位

 22 

 23     Port& Set(Pin pin);                        // 设置引脚,并应用配置。

 24         bool Empty() const { return _Pin == P0; }

 25 

 26     virtual void Config();                // 确定配置,确认用对象内部的参数进行初始化

 27 

 28     // 辅助函数

 29     _force_inline static GPIO_TypeDef* IndexToGroup(byte index);

 30     _force_inline static byte GroupToIndex(GPIO_TypeDef* group);

 31 

 32 #if DEBUG

 33         static bool Reserve(Pin pin, bool flag);        // 保护引脚,别的功能要使用时将会报错。返回是否保护成功

 34         static bool IsBusy(Pin pin);        // 引脚是否被保护

 35 #endif

 36 

 37 protected:

 38         Port();

 39         virtual ~Port();

 40 

 41     // 配置过程,由Config调用,最后GPIO_Init

 42     virtual void OnConfig(GPIO_InitTypeDef& gpio);

 43 #if DEBUG

 44         virtual bool OnReserve(Pin pin, bool flag);

 45 #endif

 46 

 47 private:

 48 #if defined(STM32F1)

 49         ulong InitState;        // 备份引脚初始状态,在析构时还原

 50 #endif

 51 };

 52 

 53 // 输出口

 54 class OutputPort : public Port

 55 {

 56 public:

 57     bool OpenDrain;        // 是否开漏输出

 58     bool Invert;        // 是否倒置输入输出

 59     uint Speed;                // 速度

 60 

 61     OutputPort() { Init(); }

 62         // 普通输出一般采用开漏输出,需要倒置

 63     OutputPort(Pin pin, bool invert = false, bool openDrain = false, uint speed = GPIO_MAX_SPEED)

 64         {

 65                 Init(invert, openDrain, speed);

 66                 Set(pin);

 67         }

 68 

 69         // 整体写入所有包含的引脚

 70     void Write(bool value);

 71     void WriteGroup(ushort value);   // 整组写入

 72         void Up(uint ms);        // 拉高一段时间后拉低

 73         void Blink(uint times, uint ms);        // 闪烁多次

 74 

 75     ushort ReadGroup();    // 整组读取

 76         // 读取指定索引引脚。索引按照从小到大,0xFF表示任意脚为true则返回true

 77     bool Read(byte index);

 78     bool Read();                // Read() ReadReal() 的区别在  前者读输出  一个读输入    在开漏输出的时候有很大区别

 79         bool ReadInput();

 80 

 81     static bool Read(Pin pin);

 82     static void Write(Pin pin, bool value);

 83 

 84     OutputPort& operator=(bool value) { Write(value); return *this; }

 85     OutputPort& operator=(OutputPort& port) { Write(port.Read()); return *this; }

 86     operator bool() { return Read(); }

 87 

 88 protected:

 89     virtual void OnConfig(GPIO_InitTypeDef& gpio);

 90 

 91     void Init(bool invert = false, bool openDrain = false, uint speed = GPIO_MAX_SPEED)

 92     {

 93         OpenDrain = openDrain;

 94         Speed = speed;

 95         Invert = invert;

 96     }

 97 

 98 #if DEBUG

 99         virtual bool OnReserve(Pin pin, bool flag);

100 #endif

101 };

102 

103 // 复用输出口

104 class AlternatePort : public OutputPort

105 {

106 public:

107         AlternatePort() : OutputPort() { Init(false, false); }

108         // 复用输出一般采用推挽输出,不需要倒置

109     AlternatePort(Pin pin, bool invert = false, bool openDrain = false, uint speed = GPIO_MAX_SPEED)

110                 : OutputPort()

111         {

112                 Init(invert, openDrain, speed);

113                 Set(pin);

114         }

115 

116 protected:

117     virtual void OnConfig(GPIO_InitTypeDef& gpio);

118 

119 #if DEBUG

120         virtual bool OnReserve(Pin pin, bool flag);

121 #endif

122 };

123 

124 // 输入口

125 class InputPort : public Port

126 {

127 public:

128     typedef enum

129     {

130         PuPd_NOPULL = 0x00,

131         PuPd_UP     = 0x01,

132         PuPd_DOWN   = 0x02

133     }PuPd_TypeDef;

134 

135     // 读取委托

136     typedef void (*IOReadHandler)(Pin pin, bool down, void* param);

137 

138     uint ShakeTime;     // 抖动时间

139     PuPd_TypeDef PuPd;  // 上拉下拉电阻

140     bool Floating;      // 是否浮空输入

141     bool Invert;                // 是否倒置输入输出

142 

143         InputPort() { Init(); }

144     InputPort(Pin pin, bool floating = true, PuPd_TypeDef pupd = PuPd_UP)

145         {

146                 Init(floating, pupd);

147                 Set(pin);

148         }

149 

150     virtual ~InputPort();

151 

152     ushort ReadGroup();                        // 整组读取

153     bool Read();                                // 读取状态

154     static bool Read(Pin pin);        // 读取某个引脚

155 

156     void Register(IOReadHandler handler, void* param = NULL);   // 注册事件

157 

158     operator bool() { return Read(); }

159 

160 protected:

161     // 函数命名为Init,而不作为构造函数,主要是因为用构造函数会导致再实例化一个对象,然后这个函数在那个新对象里面执行

162     void Init(bool floating = true, PuPd_TypeDef pupd = PuPd_UP)

163     {

164                 PuPd = pupd;

165         Floating = floating;

166 

167         _Registed = false;

168         //ShakeTime = 20;

169                 // 有些应用的输入口需要极高的灵敏度,这个时候不需要抖动检测

170         ShakeTime = 0;

171         Invert = false;

172     }

173 

174     virtual void OnConfig(GPIO_InitTypeDef& gpio);

175 

176 #if DEBUG

177         virtual bool OnReserve(Pin pin, bool flag);

178 #endif

179 

180 private:

181     bool _Registed;

182 

183     void RegisterInput(int groupIndex, int pinIndex, IOReadHandler handler, void* param);

184     void UnRegisterInput(int pinIndex);

185 };

186 

187 // 模拟输入输出口

188 class AnalogInPort : public Port

189 {

190 public:

191     AnalogInPort(Pin pin) { Set(pin); }

192 

193 protected:

194     virtual void OnConfig(GPIO_InitTypeDef& gpio);

195 };

196 

197 // 输出端口会话类。初始化时打开端口,超出作用域析构时关闭。反向操作可配置端口为倒置

198 class PortScope

199 {

200 private:

201         OutputPort* _port;

202         bool _value;

203 

204 public:

205         PortScope(OutputPort* port, bool value = true)

206         {

207                 _port = port;

208                 if(_port)

209                 {

210                         // 备份数值,析构的时候需要还原

211                         _value = port->Read();

212                         *_port = value;

213                 }

214         }

215 

216         ~PortScope()

217         {

218                 if(_port) *_port = _value;

219         }

220 };

221 

222 #endif //_Port_H_

223 源码实现

224 

225 #include "Port.h"

226 

227 #if defined(STM32F1) || defined(STM32F4)

228 static const int PORT_IRQns[] = {

229     EXTI0_IRQn, EXTI1_IRQn, EXTI2_IRQn, EXTI3_IRQn, EXTI4_IRQn, // 5个基础的

230     EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn, EXTI9_5_IRQn,    // EXTI9_5

231     EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn, EXTI15_10_IRQn   // EXTI15_10

232 };

233 #elif defined(STM32F0)

234 static const int PORT_IRQns[] = {

235     EXTI0_1_IRQn, EXTI0_1_IRQn, // 基础

236     EXTI2_3_IRQn, EXTI2_3_IRQn, // 基础

237     EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn,

238     EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn, EXTI4_15_IRQn   // EXTI15_10

239 };

240 #endif

241 

242 // 端口基本功能

243 #define REGION_Port 1

244 #ifdef REGION_Port

245 Port::Port()

246 {

247         _Pin = P0;

248         Group = NULL;

249         PinBit = 0;

250 }

251 

252 Port::~Port()

253 {

254 #if defined(STM32F1)

255         // 恢复为初始化状态

256         ushort bits = PinBit;

257         int config = InitState & 0xFFFFFFFF;

258         for(int i=0; i<16 && bits; i++, bits>>=1)

259         {

260                 if(i == 7) config = InitState >> 32;

261                 if(bits & 1)

262                 {

263                         uint shift = (i & 7) << 2; // 每引脚4位

264                         uint mask = 0xF << shift;  // 屏蔽掉其它位

265 

266                         GPIO_TypeDef* port = Group;

267                         if (i & 0x08) { // bit 8 - 15

268                                 port->CRH = port->CRH & ~mask | (config & mask);

269                         } else { // bit 0-7

270                                 port->CRL = port->CRL & ~mask | (config & mask);

271                         }

272                 }

273         }

274 #endif

275 

276 #if DEBUG

277         // 解除保护引脚

278         OnReserve(_Pin, false);

279 #endif

280 }

281 

282 // 单一引脚初始化

283 Port& Port::Set(Pin pin)

284 {

285         //assert_param(pin != P0);

286 

287 #if DEBUG

288         if(_Pin != P0) OnReserve(_Pin, false);

289 #endif

290 

291     _Pin = pin;

292         if(_Pin != P0)

293         {

294                 Group = IndexToGroup(pin >> 4);

295                 PinBit = 1 << (pin & 0x0F);

296         }

297         else

298         {

299                 Group = NULL;

300                 PinBit = 0;

301         }

302 

303 #if defined(STM32F1)

304         // 整组引脚的初始状态,析构时有选择恢复

305         if(_Pin != P0) InitState = ((ulong)Group->CRH << 32) + Group->CRL;

306 #endif

307 

308 #if DEBUG

309         // 保护引脚

310         if(_Pin != P0) OnReserve(_Pin, true);

311 #endif

312 

313         if(_Pin != P0) Config();

314 

315         return *this;

316 }

317 

318 void Port::Config()

319 {

320         GPIO_InitTypeDef gpio;

321         // 特别要慎重,有些结构体成员可能因为没有初始化而酿成大错

322         GPIO_StructInit(&gpio);

323 

324     OnConfig(gpio);

325     GPIO_Init(Group, &gpio);

326 }

327 

328 void Port::OnConfig(GPIO_InitTypeDef& gpio)

329 {

330     // 打开时钟

331     int gi = _Pin >> 4;

332 #ifdef STM32F0

333     RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOAEN << gi, ENABLE);

334 #elif defined(STM32F1)

335     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA << gi, ENABLE);

336 #elif defined(STM32F4)

337     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA << gi, ENABLE);

338 #endif

339 

340     gpio.GPIO_Pin = PinBit;

341 

342 #ifdef STM32F1

343         // PA15/PB3/PB4 需要关闭JTAG

344         switch(_Pin)

345         {

346                 case PA15:

347                 case PB3:

348                 case PB4:

349                 {

350                         debug_printf("Close JTAG for P%c%d\r\n", _PIN_NAME(_Pin));

351 

352                         // PA15是jtag接口中的一员 想要使用 必须开启remap

353                         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

354                         GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);

355                         break;

356                 }

357         }

358 #endif

359 }

360 

361 GPIO_TypeDef* Port::IndexToGroup(byte index) { return ((GPIO_TypeDef *) (GPIOA_BASE + (index << 10))); }

362 byte Port::GroupToIndex(GPIO_TypeDef* group) { return (byte)(((int)group - GPIOA_BASE) >> 10); }

363 #endif

364 

365 // 端口引脚保护

366 #if DEBUG

367 static ushort Reserved[8];                // 引脚保留位,记录每个引脚是否已经被保留,禁止别的模块使用

368 

369 // 保护引脚,别的功能要使用时将会报错。返回是否保护成功

370 bool Port::Reserve(Pin pin, bool flag)

371 {

372     int port = pin >> 4, bit = 1 << (pin & 0x0F);

373     if (flag) {

374         if (Reserved[port] & bit) {

375                         // 增加针脚已经被保护的提示,很多地方调用ReservePin而不写日志,得到False后直接抛异常

376                         debug_printf("ReservePin P%c%d already reserved\r\n", _PIN_NAME(pin));

377                         return false; // already reserved

378                 }

379         Reserved[port] |= bit;

380 

381                 debug_printf("ReservePin P%c%d\r\n", _PIN_NAME(pin));

382     } else {

383         Reserved[port] &= ~bit;

384 

385 #if defined(STM32F1)

386                 int config = 0;

387                 uint shift = (pin & 7) << 2; // 4 bits / pin

388                 uint mask = 0xF << shift; // 屏蔽掉其它位

389                 GPIO_TypeDef* port2 = IndexToGroup(port); // pointer to the actual port registers

390                 if (pin & 0x08) { // bit 8 - 15

391                         config = port2->CRH & mask;

392                 } else { // bit 0-7

393                         config = port2->CRL & mask;

394                 }

395 

396                 config >>= shift;        // 移位到最右边

397                 config &= 0xF;

398                 debug_printf("UnReservePin P%c%d Config=0x%02x\r\n", _PIN_NAME(pin), config);

399 #else

400                 debug_printf("UnReservePin P%c%d\r\n", _PIN_NAME(pin));

401 #endif

402         }

403 

404     return true;

405 }

406 

407 bool Port::OnReserve(Pin pin, bool flag)

408 {

409         return Reserve(pin, flag);

410 }

411 

412 bool OutputPort::OnReserve(Pin pin, bool flag)

413 {

414         debug_printf("Output::");

415 

416         return Port::OnReserve(pin, flag);

417 }

418 

419 bool AlternatePort::OnReserve(Pin pin, bool flag)

420 {

421         debug_printf("Alternate::");

422 

423         return Port::OnReserve(pin, flag);

424 }

425 

426 bool InputPort::OnReserve(Pin pin, bool flag)

427 {

428         debug_printf("Input::");

429 

430         return Port::OnReserve(pin, flag);

431 }

432 

433 // 引脚是否被保护

434 bool Port::IsBusy(Pin pin)

435 {

436     int port = pin >> 4, sh = pin & 0x0F;

437     return (Reserved[port] >> sh) & 1;

438 }

439 #endif

440 

441 // 引脚配置

442 #define REGION_Config 1

443 #ifdef REGION_Config

444 void OutputPort::OnConfig(GPIO_InitTypeDef& gpio)

445 {

446 #ifndef STM32F4

447         assert_param(Speed == 2 || Speed == 10 || Speed == 50);

448 #else

449         assert_param(Speed == 2 || Speed == 25 || Speed == 50 || Speed == 100);

450 #endif

451 

452         Port::OnConfig(gpio);

453 

454         switch(Speed)

455         {

456                 case 2: gpio.GPIO_Speed = GPIO_Speed_2MHz; break;

457 #ifndef STM32F4

458                 case 10: gpio.GPIO_Speed = GPIO_Speed_10MHz; break;

459 #else

460                 case 25: gpio.GPIO_Speed = GPIO_Speed_25MHz; break;

461                 case 100: gpio.GPIO_Speed = GPIO_Speed_100MHz; break;

462 #endif

463                 case 50: gpio.GPIO_Speed = GPIO_Speed_50MHz; break;

464         }

465 

466 #ifdef STM32F1

467         gpio.GPIO_Mode = OpenDrain ? GPIO_Mode_Out_OD : GPIO_Mode_Out_PP;

468 #else

469         gpio.GPIO_Mode = GPIO_Mode_OUT;

470         gpio.GPIO_OType = OpenDrain ? GPIO_OType_OD : GPIO_OType_PP;

471 #endif

472 

473         // 配置之前,需要根据倒置情况来设定初始状态,也就是在打开端口之前必须明确端口高低状态

474         ushort dat = GPIO_ReadOutputData(Group);

475         if(!Invert)

476                 dat &= ~PinBit;

477         else

478                 dat |= PinBit;

479         GPIO_Write(Group, dat);

480 }

481 

482 void AlternatePort::OnConfig(GPIO_InitTypeDef& gpio)

483 {

484         OutputPort::OnConfig(gpio);

485 

486 #ifdef STM32F1

487         gpio.GPIO_Mode = OpenDrain ? GPIO_Mode_AF_OD : GPIO_Mode_AF_PP;

488 #else

489         gpio.GPIO_Mode = GPIO_Mode_AF;

490         gpio.GPIO_OType = OpenDrain ? GPIO_OType_OD : GPIO_OType_PP;

491 #endif

492 }

493 

494 void InputPort::OnConfig(GPIO_InitTypeDef& gpio)

495 {

496         Port::OnConfig(gpio);

497 

498 #ifdef STM32F1

499         if(Floating)

500                 gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;

501         else if(PuPd == PuPd_UP)

502                 gpio.GPIO_Mode = GPIO_Mode_IPU;

503         else if(PuPd == PuPd_DOWN)

504                 gpio.GPIO_Mode = GPIO_Mode_IPD; // 这里很不确定,需要根据实际进行调整

505 #else

506         gpio.GPIO_Mode = GPIO_Mode_IN;

507         //gpio.GPIO_OType = !Floating ? GPIO_OType_OD : GPIO_OType_PP;

508 #endif

509 }

510 

511 void AnalogInPort::OnConfig(GPIO_InitTypeDef& gpio)

512 {

513         Port::OnConfig(gpio);

514 

515 #ifdef STM32F1

516         gpio.GPIO_Mode = GPIO_Mode_AIN; //

517 #else

518         gpio.GPIO_Mode = GPIO_Mode_AN;

519         //gpio.GPIO_OType = !Floating ? GPIO_OType_OD : GPIO_OType_PP;

520 #endif

521 }

522 #endif

523 

524 // 输出端口

525 #define REGION_Output 1

526 #ifdef REGION_Output

527 ushort OutputPort::ReadGroup()    // 整组读取

528 {

529         return GPIO_ReadOutputData(Group);

530 }

531 

532 bool OutputPort::Read()

533 {

534         // 转为bool时会转为0/1

535         bool rs = GPIO_ReadOutputData(Group) & PinBit;

536         return rs ^ Invert;

537 }

538 

539 bool OutputPort::ReadInput()

540 {

541         bool rs = GPIO_ReadInputData(Group) & PinBit;

542         return rs ^ Invert;

543 }

544 

545 bool OutputPort::Read(Pin pin)

546 {

547         GPIO_TypeDef* group = _GROUP(pin);

548         return (group->IDR >> (pin & 0xF)) & 1;

549 }

550 

551 void OutputPort::Write(bool value)

552 {

553     if(value ^ Invert)

554         GPIO_SetBits(Group, PinBit);

555     else

556         GPIO_ResetBits(Group, PinBit);

557 }

558 

559 void OutputPort::WriteGroup(ushort value)

560 {

561     GPIO_Write(Group, value);

562 }

563 

564 void OutputPort::Up(uint ms)

565 {

566     Write(true);

567         Sys.Sleep(ms);

568     Write(false);

569 }

570 

571 void OutputPort::Blink(uint times, uint ms)

572 {

573         bool flag = true;

574     for(int i=0; i<times; i++)

575         {

576                 Write(flag);

577                 flag = !flag;

578                 Sys.Sleep(ms);

579         }

580     Write(false);

581 }

582 

583 // 设置端口状态

584 void OutputPort::Write(Pin pin, bool value)

585 {

586     if(value)

587         GPIO_SetBits(_GROUP(pin), _PORT(pin));

588     else

589         GPIO_ResetBits(_GROUP(pin), _PORT(pin));

590 }

591 #endif

592 

593 // 输入端口

594 #define REGION_Input 1

595 #ifdef REGION_Input

596 /* 中断状态结构体 */

597 /* 一共16条中断线,意味着同一条线每一组只能有一个引脚使用中断 */

598 typedef struct TIntState

599 {

600     Pin Pin;

601     InputPort::IOReadHandler Handler;        // 委托事件

602         void* Param;        // 事件参数,一般用来作为事件挂载者的对象,然后借助静态方法调用成员方法

603     bool OldValue;

604 

605     uint ShakeTime;     // 抖动时间

606     int Used;   // 被使用次数。对于前5行中断来说,这个只会是1,对于后面的中断线来说,可能多个

607 } IntState;

608 

609 // 16条中断线

610 static IntState State[16];

611 static bool hasInitState = false;

612 

613 void RegisterInput(int groupIndex, int pinIndex, InputPort::IOReadHandler handler);

614 void UnRegisterInput(int pinIndex);

615 

616 InputPort::~InputPort()

617 {

618     // 取消所有中断

619     if(_Registed) Register(NULL);

620 }

621 

622 ushort InputPort::ReadGroup()    // 整组读取

623 {

624         return GPIO_ReadInputData(Group);

625 }

626 

627 // 读取本组所有引脚,任意脚为true则返回true,主要为单一引脚服务

628 bool InputPort::Read()

629 {

630         // 转为bool时会转为0/1

631         bool rs = GPIO_ReadInputData(Group) & PinBit;

632         return rs ^ Invert;

633 }

634 

635 bool InputPort::Read(Pin pin)

636 {

637         GPIO_TypeDef* group = _GROUP(pin);

638         return (group->IDR >> (pin & 0xF)) & 1;

639 }

640 

641 // 注册回调  及中断使能

642 void InputPort::Register(IOReadHandler handler, void* param)

643 {

644     if(!PinBit) return;

645 

646     // 检查并初始化中断线数组

647     if(!hasInitState)

648     {

649         for(int i=0; i<16; i++)

650         {

651             IntState* state = &State[i];

652             state->Pin = P0;

653             state->Handler = NULL;

654             state->Used = 0;

655         }

656         hasInitState = true;

657     }

658 

659     byte gi = _Pin >> 4;

660     ushort n = PinBit;

661     for(int i=0; i<16 && n!=0; i++)

662     {

663         // 如果设置了这一位,则注册事件

664         if(n & 0x01)

665         {

666             // 注册中断事件

667             if(handler)

668             {

669                 IntState* state = &State[i];

670                 state->ShakeTime = ShakeTime;

671                 RegisterInput(gi, i, handler, param);

672             }

673             else

674                 UnRegisterInput(i);

675         }

676         n >>= 1;

677     }

678 

679     _Registed = handler != NULL;

680 }

681 

682 #define IT 1

683 #ifdef IT

684 void GPIO_ISR (int num)  // 0 <= num <= 15

685 {

686         if(!hasInitState) return;

687 

688         IntState* state = State + num;

689         if(!state) return;

690 

691         uint bit = 1 << num;

692         bool value;

693         //byte line = EXTI_Line0 << num;

694         // 如果未指定委托,则不处理

695         if(!state->Handler) return;

696 

697         // 默认20us抖动时间

698         uint shakeTime = state->ShakeTime;

699 

700         do {

701                 EXTI->PR = bit;   // 重置挂起位

702                 value = InputPort::Read(state->Pin); // 获取引脚状态

703                 if(shakeTime > 0)

704                 {

705                         // 值必须有变动才触发

706                         if(value == state->OldValue) return;

707 

708                         Time.Sleep(shakeTime); // 避免抖动

709                 }

710         } while (EXTI->PR & bit); // 如果再次挂起则重复

711         //EXTI_ClearITPendingBit(line);

712         // 值必须有变动才触发

713         if(shakeTime > 0 && value == state->OldValue) return;

714         state->OldValue = value;

715         if(state->Handler)

716         {

717                 // 新值value为true,说明是上升,第二个参数是down,所以取非

718                 state->Handler(state->Pin, !value, state->Param);

719         }

720 }

721 

722 void EXTI_IRQHandler(ushort num, void* param)

723 {

724 #if defined(STM32F1) || defined(STM32F4)

725         // EXTI0 - EXTI4

726         if(num <= EXTI4_IRQn)

727                 GPIO_ISR(num - EXTI0_IRQn);

728         else if(num == EXTI9_5_IRQn)

729         {

730                 // EXTI5 - EXTI9

731                 uint pending = EXTI->PR & EXTI->IMR & 0x03E0; // pending bits 5..9

732                 int num = 5; pending >>= 5;

733                 do {

734                         if (pending & 1) GPIO_ISR(num);

735                         num++; pending >>= 1;

736                 } while (pending);

737         }

738         else if(num == EXTI15_10_IRQn)

739         {

740                 // EXTI10 - EXTI15

741                 uint pending = EXTI->PR & EXTI->IMR & 0xFC00; // pending bits 10..15

742                 int num = 10; pending >>= 10;

743                 do {

744                         if (pending & 1) GPIO_ISR(num);

745                         num++; pending >>= 1;

746                 } while (pending);

747         }

748 #elif defined(STM32F0)

749         switch(num)

750         {

751                 case EXTI0_1_IRQn:

752                 {

753                         uint pending = EXTI->PR & EXTI->IMR & 0x0003; // pending bits 0..1

754                         int num = 0; pending >>= 0;

755                         do {

756                                 if (pending & 1) GPIO_ISR(num);

757                                 num++; pending >>= 1;

758                         } while (pending);

759                         break;

760                 }

761                 case EXTI2_3_IRQn:

762                 {

763                         uint pending = EXTI->PR & EXTI->IMR & 0x000c; // pending bits 3..2

764                         int num = 2; pending >>= 2;

765                         do {

766                                 if (pending & 1) GPIO_ISR(num);

767                                 num++; pending >>= 1;

768                         } while (pending);

769                 }

770                 case EXTI4_15_IRQn:

771                 {

772                         uint pending = EXTI->PR & EXTI->IMR & 0xFFF0; // pending bits 4..15

773                         int num = 4; pending >>= 4;

774                         do {

775                                 if (pending & 1) GPIO_ISR(num);

776                                 num++; pending >>= 1;

777                         } while (pending);

778                 }

779         }

780 #endif

781 }

782 #endif

783 

784 void SetEXIT(int pinIndex, bool enable)

785 {

786     /* 配置EXTI中断线 */

787     EXTI_InitTypeDef ext;

788     EXTI_StructInit(&ext);

789     ext.EXTI_Line = EXTI_Line0 << pinIndex;

790     ext.EXTI_Mode = EXTI_Mode_Interrupt;

791     ext.EXTI_Trigger = EXTI_Trigger_Rising_Falling; // 上升沿下降沿触发

792     ext.EXTI_LineCmd = enable ? ENABLE : DISABLE;

793     EXTI_Init(&ext);

794 }

795 

796 // 申请引脚中断托管

797 void InputPort::RegisterInput(int groupIndex, int pinIndex, IOReadHandler handler, void* param)

798 {

799     IntState* state = &State[pinIndex];

800     Pin pin = (Pin)((groupIndex << 4) + pinIndex);

801     // 检查是否已经注册到别的引脚上

802     if(state->Pin != pin && state->Pin != P0)

803     {

804 #if DEBUG

805         debug_printf("EXTI%d can't register to P%c%d, it has register to P%c%d\r\n", groupIndex, _PIN_NAME(pin), _PIN_NAME(state->Pin));

806 #endif

807         return;

808     }

809     state->Pin = pin;

810     state->Handler = handler;

811         state->Param = param;

812         state->OldValue = Read(pin); // 预先保存当前状态值,后面跳变时触发中断

813 

814     // 打开时钟,选择端口作为端口EXTI时钟线

815 #if defined(STM32F0) || defined(STM32F4)

816     RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);

817     SYSCFG_EXTILineConfig(groupIndex, pinIndex);

818 #elif defined(STM32F1)

819     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

820     GPIO_EXTILineConfig(groupIndex, pinIndex);

821 #endif

822 

823         SetEXIT(pinIndex, true);

824 

825     // 打开并设置EXTI中断为低优先级

826     Interrupt.SetPriority(PORT_IRQns[pinIndex], 1);

827 

828     state->Used++;

829     if(state->Used == 1)

830     {

831         Interrupt.Activate(PORT_IRQns[pinIndex], EXTI_IRQHandler, this);

832     }

833 }

834 

835 void InputPort::UnRegisterInput(int pinIndex)

836 {

837     IntState* state = &State[pinIndex];

838     // 取消注册

839     state->Pin = P0;

840     state->Handler = 0;

841 

842         SetEXIT(pinIndex, false);

843 

844     state->Used--;

845     if(state->Used == 0)

846     {

847         Interrupt.Deactivate(PORT_IRQns[pinIndex]);

848     }

849 }

850 #endif

 

End!
欢迎大家一起交流 ,分享程序员励志故事。   幸福的程序员 QQ群:幸福的程序员 智能硬件群
中国嵌入式物联网群
 

 

你可能感兴趣的:(port)