# 11.01_HALL-HALL状态值和IO对应关系

## 测试步骤

给hall口提供电压，记录输入到IO的电平以及hall状态。

GPIO | AF
--- | ---
P0.5 | HALL_IN0
P0.6 | HALL_IN1
P0.7 | HALL_IN2

## 实测数据

t | HALL_IN0 | HALL_IN1 | HALL_IN2 | hall_val | hall_fltval
--- | --- | --- | --- | --- | ---
0 | 0 | 0 | 0 | 0 | 0
1 | 1 | 0 | 0 | 1 | 1
2 | 0 | 1 | 0 | 2 | 2
3 | 1 | 1 | 0 | 3 | 3
4 | 0 | 0 | 1 | 4 | 4
5 | 1 | 0 | 1 | 5 | 5
6 | 0 | 1 | 1 | 6 | 6
7 | 1 | 1 | 1 | 7 | 7
8 | 0 | 0 | 0 | 0 | 0
9 | 1 | 0 | 0 | 1 | 1
10 | 0 | 1 | 0 | 2 | 2
11 | 1 | 1 | 0 | 3 | 3
12 | 0 | 0 | 1 | 4 | 4
13 | 1 | 0 | 1 | 5 | 5

## 参考代码

11.01_HALL_Count.c

    /**
     * @brief HALL-HALL状态值和IO对应关系
     * @details
     * 给hall口提供电压，记录输入到IO的电平以及hall状态。
     * |GPIO|AF|
     * |-|-|
     * |P0.5|HALL_IN0|
     * |P0.6|HALL_IN1|
     * |P0.7|HALL_IN2|
     *
     */
    #include "lks32mc09x_gpio.h"
    #include "lks32mc09x_hall.h"
    volatile uint32_t hall_val;    // 当前霍尔值
    volatile uint32_t hall_fltval; // 滤波后的霍尔值
    /**
     * @brief 主函数，用于测试HSI时钟输出及GPIO翻转
     */
    int main(void)
    {
        GPIO_Config(GPIO0, GPIO_PinSource_5, GPIO_Mode_IN, GPIO_AF_HALL); // HALL_IN0
        GPIO_Config(GPIO0, GPIO_PinSource_6, GPIO_Mode_IN, GPIO_AF_HALL); // HALL_IN1
        GPIO_Config(GPIO0, GPIO_PinSource_7, GPIO_Mode_IN, GPIO_AF_HALL); // HALL_IN2

        HALL_InitTypeDef HALL_InitStruct;

        HALL_StructInit(&HALL_InitStruct);

        HALL_InitStruct.FilterLen = 10;                /* Hall信号数字滤波长度 512个时钟周期 */
        HALL_InitStruct.ClockDivision = HALL_CLK_DIV1; /* 设置Hall模块时钟分频系数 */
        HALL_InitStruct.Filter75_Ena = ENABLE;         /* Hall信号滤波方式，7判5模式或者全1有效模式 */
        HALL_InitStruct.HALL_Ena = ENABLE;             /* 模块使能 */
        HALL_InitStruct.Capture_IRQ_Ena = ENABLE;      /* 捕捉中断使能 */
        HALL_InitStruct.OverFlow_IRQ_Ena = ENABLE;     /* 超时中断使能 */
        HALL_InitStruct.CountTH = 960000;              /* Hall模块计数模值，计数超过模值会产生超时中断 */
        HALL_InitStruct.softIE = ENABLE;               /* 软件中断失能 */

        HALL_Init(&HALL_InitStruct); /* HALL初化 */
        HALL_Cmd(ENABLE);            /* HALL使能 */

        while (1)
        {
            hall_val = HALL_GetCaptureValue();
            hall_fltval = HALL_GetFilterValue();
        }
    }

## 使用到的库函数

库函数部分代码

    #define GPIO_AF_I2C 6
    #define HALL0 ((HALL_TypeDef *)HALL0_BASE)
    #define HALL_CAPTURE_EVENT ((uint32_t)0x00010000)
    #define HALL_OVERFLOW_EVENT ((uint32_t)0x00020000)
    #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_HALL0 BIT3
    /**
     * @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 HALL初始化结构体句柄，初始化时请定义该句柄，并用其它地址来传参
     */
    typedef struct HALL_InitTypeDef {
        uint32_t CountTH;
        uint16_t FilterLen;
        uint8_t ClockDivision;
        uint8_t Filter75_Ena;
        uint8_t HALL_Ena;
        uint8_t Capture_IRQ_Ena;
        uint8_t OverFlow_IRQ_Ena;
        uint8_t softIE;
    };
    /**
     * @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 使能或失能HALL模块
     * @param state: 功能状态，ENABLE或DISABLE
     */
    void HALL_Cmd(uint8_t state)
    {
        if (state == ENABLE)
        {
            HALL0->CFG |= (1 << 24); // 使能HALL模块
        }
        else
        {
            HALL0->CFG &= ~(1 << 24); // 失能HALL模块
        }
    }
    /**
     * @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 初始化HALL模块
     * @param HALL_InitStruct: 指向HALL_InitTypeDef结构体的指针
     */
    void HALL_Init(HALL_InitTypeDef *HALL_InitStruct)
    {
        if (HALL_InitStruct != 0)
        {
            // 使能HALL模块时钟
            SYS_ModuleClockCmd(SYS_MODULE_HALL0, ENABLE);

            // 配置HALL寄存器
            HALL0->CFG &= ~(0x00FFFFFF); // 清除相关位
            HALL0->CFG |= (HALL_InitStruct->Filter75_Ena << 20) |
                          (HALL_InitStruct->ClockDivision << 16) |
                          (HALL_InitStruct->FilterLen & 0xFFFF);

            HALL0->TH = HALL_InitStruct->CountTH;

            // 配置中断使能
            HALL0->CFG &= ~(HALL_CAPTURE_EVENT | HALL_OVERFLOW_EVENT);
            HALL0->CFG |= (HALL_InitStruct->Capture_IRQ_Ena << 28) |
                          (HALL_InitStruct->OverFlow_IRQ_Ena << 29) |
                          (HALL_InitStruct->softIE << 30);

            // 使能HALL模块
            HALL0->CFG |= (HALL_InitStruct->HALL_Ena << 24);
        }
        else
        {
            __NOP();
        }
    }
    /**
     * @brief 初始化HALL结构体
     * @param HALL_InitStruct: 指向HALL_InitTypeDef结构体的指针
     */
    void HALL_StructInit(HALL_InitTypeDef *HALL_InitStruct)
    {
        if (HALL_InitStruct != 0)
        {
            HALL_InitStruct->CountTH          = 0;
            HALL_InitStruct->FilterLen        = 0;
            HALL_InitStruct->ClockDivision    = 0;
            HALL_InitStruct->Filter75_Ena     = DISABLE;
            HALL_InitStruct->HALL_Ena         = DISABLE;
            HALL_InitStruct->Capture_IRQ_Ena  = DISABLE;
            HALL_InitStruct->OverFlow_IRQ_Ena = DISABLE;
            HALL_InitStruct->softIE           = DISABLE;
        }
        else
        {
            __NOP();
        }
    }
    /**
     * @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 读取未滤波的HALL值
     * @return 未滤波的HALL值
     */
    uint32_t HALL_GetCaptureValue(void)
    {
        return (HALL0->INFO >> 8) & 0x07;
    }
    /**
     * @brief 读取滤波后的HALL值
     * @return 滤波后的HALL值
     */
    uint32_t HALL_GetFilterValue(void)
    {
        return (HALL0->INFO & 0x07);
    }
    /**
     * @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;
        }
    }