17.02_QEP-符号加脉冲信号计数
测试步骤
设置P2.11(QEP0_CH0), P2.12(QEP0_CH1)和P0.13(QEP0_Z);
实测数据
CCWSIGN_UpDown
qep_cnt = 0
| time | a | b | z | cnt |
|---|---|---|---|---|
| 0 | 0 | 1 | 0 | 0 |
| 1 | 1 | 1 | 0 | 1 |
| 2 | 0 | 1 | 0 | 2 |
| 3 | 1 | 1 | 0 | 3 |
| 4 | 0 | 1 | 0 | 4 |
| 5 | 1 | 1 | 0 | 5 |
| 6 | 0 | 1 | 0 | 6 |
| 7 | 1 | 1 | 0 | 7 |
| 8 | 0 | 1 | 0 | 8 |
| 9 | 1 | 1 | 0 | 9 |
| 10 | 0 | 1 | 0 | 10 |
| 11 | 1 | 1 | 0 | 11 |
| 12 | 0 | 1 | 0 | 12 |
| 13 | 1 | 1 | 0 | 13 |
| 14 | 0 | 1 | 0 | 14 |
| 15 | 1 | 1 | 0 | 15 |
| 16 | 1 | 0 | 0 | 15 |
| 17 | 0 | 0 | 0 | 14 |
| 18 | 1 | 0 | 0 | 13 |
| 19 | 0 | 0 | 0 | 12 |
| 20 | 1 | 0 | 0 | 11 |
| 21 | 0 | 0 | 0 | 10 |
| 22 | 1 | 0 | 0 | 9 |
| 23 | 0 | 0 | 0 | 8 |
| 24 | 1 | 0 | 0 | 7 |
| 25 | 0 | 0 | 0 | 6 |
| 26 | 1 | 0 | 0 | 5 |
| 27 | 0 | 0 | 0 | 4 |
| 28 | 1 | 0 | 0 | 3 |
| 29 | 0 | 0 | 0 | 2 |
| 30 | 1 | 0 | 0 | 1 |
| 31 | 0 | 0 | 0 | 0 |
参考代码
17.02_QEP_Count.c
/**
* @brief QEP-符号加脉冲信号计数
* @details
* 设置P2.11(QEP0_CH0), P2.12(QEP0_CH1)和P0.13(QEP0_Z);
*/
#include "lks32mc09x_gpio.h"
#include "lks32mc09x_qep.h"
volatile uint32_t qep_cnt;
/**
* @brief 主函数
*/
int main(void)
{
// 配置QEP模块
QEP_InitTypeDef QEP_InitStruct;
QEP_StructInit(&QEP_InitStruct); // 初始化QEP结构体为默认值
QEP_InitStruct.Mode = QEP_Mode_CCWSIGN_UpDown; ///< 编码器模式选择
QEP_InitStruct.FE_CNT_EN = ENABLE; ///< 下降沿计数使能
QEP_InitStruct.ZC = QEP_ZC_NONE; ///< 上升沿清零
QEP_InitStruct.TH = 65535; ///< QEP计数门限寄存器
QEP_InitStruct.ClockDiv = 0; ///< 时钟分频
QEP_InitStruct.Filter = 0; ///< 信号输入滤波
QEP_InitStruct.IRQEna = 0; ///< 中断使能
QEP_Init(QEP0, &QEP_InitStruct); // 初始化QEP0模块
// 配置需要使用的gpio
GPIO_Config(GPIO2, GPIO_PinSource_11, GPIO_Mode_IN, GPIO_AF_QEP0);
GPIO_Config(GPIO2, GPIO_PinSource_12, GPIO_Mode_IN, GPIO_AF_QEP0);
GPIO_Config(GPIO0, GPIO_PinSource_13, GPIO_Mode_IN, GPIO_AF_QEP0);
// 主循环
while (1)
{
qep_cnt = QEP_GetCount(QEP0);
}
}
使用到的库函数
库函数部分代码
#define GPIO_AF_I2C 6
#define QEP0 ((QEP_TypeDef *)QEP0_BASE)
#define REG_RESET(reg,mask) reg &= ~(mask)
#define REG_SET(reg,mask) reg |= (mask)
#define REG_WRITE(reg,mask) reg = (mask)
#define SYS0 ((SYS_TypeDef *)(SYS_BASE))
#define SYS_MODULE_GPIO BIT11
#define SYS_MODULE_QEP0 BIT8
#define SYS_MODULE_TIMER0 BIT4
#define SYS_MODULE_TIMER1 BIT5
#define SYS_MODULE_TIMER2 BIT6
#define TIMER0 ((TIMER_TypeDef *)TIMER0_BASE)
#define TIMER1 ((TIMER_TypeDef *)TIMER1_BASE)
#define TIMER2 ((TIMER_TypeDef *)TIMER2_BASE)
/**
* @brief GPIO功能配置结构体句柄
*/
typedef struct GPIO_InitTypeDef {
uint32_t GPIO_Pin;
GPIO_Mode_TypeDef GPIO_Mode;
GPIO_PuPd_TypeDef GPIO_PuPd;
uint32_t GPIO_PODEna;
uint32_t GPIO_PFLT;
};
/**
* @brief GPIO模式选择枚举
*/
typedef enum GPIO_Mode_TypeDef {
GPIO_Mode_IN = 0,
GPIO_Mode_OUT = 1,
GPIO_Mode_ANA = 2,
GPIO_Mode_IO = 3,
}} {enum_name};
/**
* @brief QEP初始化结构体定义
*/
typedef struct QEP_InitTypeDef {
uint32_t Mode;
uint32_t FE_CNT_EN;
uint16_t TH;
uint32_t ClockDiv;
uint32_t Filter;
uint32_t IRQEna;
uint32_t ZC;
};
/**
* @brief GPIO配置函数
* @param GPIOx: GPIO端口
* @param GPIO_PinSource: GPIO引脚
* @param mode: GPIO模式
* @param GPIO_AF_x: GPIO复用功能选择
*/
void GPIO_Config(GPIO_TypeDef *GPIOx, uint32_t GPIO_PinSource, GPIO_Mode_TypeDef mode, uint32_t GPIO_AF_x)
{
GPIO_PinAFConfig(GPIOx, GPIO_PinSource, GPIO_AF_x);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = 1 << GPIO_PinSource;
GPIO_InitStructure.GPIO_Mode = mode;
if (GPIO_AF_x == GPIO_AF_I2C)
{
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
}
else
{
__NOP();
}
GPIO_Init(GPIOx, &GPIO_InitStructure);
}
/**
* @brief QEP初始化函数(初始化完成后会自动使能,并使能timer2)
* @param QEPx QEP模块指针
* @param TIM_QEPInitStruct 初始化结构体指针
*/
void QEP_Init(QEP_TypeDef *QEPx, QEP_InitTypeDef *TIM_QEPInitStruct)
{
// 使能QEP模块时钟
if (QEPx == QEP0)
{
SYS_ModuleClockCmd(SYS_MODULE_QEP0, ENABLE);
TIMER_Enable(TIMER2);
}
else
{
__NOP();
}
// QEP配置寄存器
QEPx->CFG = BIT15 |
(TIM_QEPInitStruct->Filter << 16) |
(TIM_QEPInitStruct->FE_CNT_EN << 10) |
(TIM_QEPInitStruct->Mode << 8) |
(TIM_QEPInitStruct->ZC);
// 设置计数门限
QEPx->TH = TIM_QEPInitStruct->TH;
// 设置中断使能
QEPx->IE = TIM_QEPInitStruct->IRQEna;
}
/**
* @brief QEP结构体初始化函数
* @param TIM_QEPInitStruct 初始化结构体指针
*/
void QEP_StructInit(QEP_InitTypeDef *TIM_QEPInitStruct)
{
for (int i = 0; i < sizeof(QEP_InitTypeDef) / sizeof(uint32_t); i++)
{
((uint32_t *)TIM_QEPInitStruct)[i] = 0;
}
}
/**
* @brief 使能Timer
* @param TIMERx Timer实例指针
*/
void TIMER_Enable(TIMER_TypeDef *TIMERx)
{
if (TIMERx == TIMER0)
{
SYS_ModuleClockCmd(SYS_MODULE_TIMER0, ENABLE);
}
else if (TIMERx == TIMER1)
{
SYS_ModuleClockCmd(SYS_MODULE_TIMER1, ENABLE);
}
else if (TIMERx == TIMER2)
{
SYS_ModuleClockCmd(SYS_MODULE_TIMER2, ENABLE);
}
else
{
__NOP();
}
}
/**
* @brief 初始化GPIO
* @param GPIOx GPIO模块指针
* @param GPIO_InitStruct 指向包含初始化参数的GPIO_InitTypeDef结构体
*/
void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)
{
// 使能GPIO时钟
SYS_ModuleClockCmd(SYS_MODULE_GPIO, ENABLE);
// 配置引脚模式
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IN)
{
GPIOx->PIE |= GPIO_InitStruct->GPIO_Pin; // 打开输入使能
GPIOx->POE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输出使能
GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉使能
}
else if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_OUT)
{
GPIOx->PIE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输入使能
GPIOx->POE |= GPIO_InitStruct->GPIO_Pin; // 使能输出
}
else if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IO)
{
GPIOx->PIE |= GPIO_InitStruct->GPIO_Pin; // 使能输入
GPIOx->POE |= GPIO_InitStruct->GPIO_Pin; // 使能输出
}
else // GPIO_Mode_ANA
{
GPIOx->PIE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输入使能
GPIOx->POE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭输出使能
GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉使能
}
if (GPIO_InitStruct->GPIO_PuPd == GPIO_PuPd_UP)
{
GPIOx->PUE |= GPIO_InitStruct->GPIO_Pin; // 使能上拉
}
else
{
GPIOx->PUE &= ~GPIO_InitStruct->GPIO_Pin; // 关闭上拉
}
// 配置开漏使能
if (GPIO_InitStruct->GPIO_PODEna)
{
GPIOx->PODE |= GPIO_InitStruct->GPIO_Pin;
}
else
{
GPIOx->PODE &= ~GPIO_InitStruct->GPIO_Pin;
}
// 配置滤波使能
if (GPIO_InitStruct->GPIO_PFLT)
{
GPIOx->PFLT |= GPIO_InitStruct->GPIO_Pin;
}
else
{
GPIOx->PFLT &= ~GPIO_InitStruct->GPIO_Pin;
}
}
/**
* @brief 初始化GPIO结构体为默认值
* @param GPIO_InitStruct 指向要初始化的GPIO_InitTypeDef结构体
*/
void GPIO_StructInit(GPIO_InitTypeDef *GPIO_InitStruct)
{
for (int i = 0; i < sizeof(GPIO_InitTypeDef); i++)
{
((uint8_t *)GPIO_InitStruct)[i] = 0;
}
}
/**
* @brief 数字模块时钟使能
* @param nModule 模块编号
* @param state 使能或禁用状态
*/
void SYS_ModuleClockCmd(uint32_t nModule, uint8_t state)
{
REG_WRITE(SYS0->PROTECT, 0x7a83);
if (state)
{
REG_SET(SYS0->CLK_FEN, nModule);
}
else
{
REG_RESET(SYS0->CLK_FEN, nModule);
}
REG_WRITE(SYS0->PROTECT, 0);
}
/**
* @brief 获取QEP计数器当前值
* @param QEPx QEP模块指针
* @return 计数器当前值
*/
uint16_t QEP_GetCount(QEP_TypeDef *QEPx)
{
return QEPx->CNT;
}
/**
* @brief 配置GPIO引脚复用功能
* @param GPIOx GPIO模块指针
* @param GPIO_PinSource 引脚源
* @param GPIO_AF 复用功能选择
*/
void GPIO_PinAFConfig(GPIO_TypeDef *GPIOx, uint32_t GPIO_PinSource, uint32_t GPIO_AF)
{
uint8_t offset;
uint8_t pins = GPIO_PinSource >> 2;
offset = ((GPIO_PinSource & 0x3) * 4);
switch (pins)
{
case 0:
GPIOx->F3210 = (GPIOx->F3210 & ~(0xf << offset)) | (GPIO_AF << offset);
break;
case 1:
GPIOx->F7654 = (GPIOx->F7654 & ~(0xf << offset)) | (GPIO_AF << offset);
break;
case 2:
GPIOx->FBA98 = (GPIOx->FBA98 & ~(0xf << offset)) | (GPIO_AF << offset);
break;
case 3:
GPIOx->FFEDC = (GPIOx->FFEDC & ~(0xf << offset)) | (GPIO_AF << offset);
break;
default:
break;
}
}