0


逐飞科技STC32G12K128开源库学习(基础)

GPIO

电平读取与改变(GPI & GPO)

读电平貌似是直接用引脚号就行,貌似默认拉高。(从led的点亮方式来看,输出也应该是直接赋值即可)

//示例

#include "headfile.h"

#define LED P52

void main()
{
    board_init();            
    
    while(1)
    {
        //将 P04 接地,就可观察到灯灭
        if(P04 == 1)
            LED = 0;
        else
            LED = 1;
    }
}

模式设定

gpio_mode(P5_4, GPO_PP);

//-------------------------------------------------------------------------------------------------------------------
// @brief GPIO设置引脚模式
// @param pin 选择引脚(P0_0-P5_4)
// @param mode 引脚模式 GPIO:准双向口, GPO_PP:推挽输出, GPI_IMPEDANCE:高阻输入, GPI_OD:开漏输出
// @return void
// Sample usage: gpio_mode(P0_0,GPIO); // 设置P0.0设置为双向IO
//-------------------------------------------------------------------------------------------------------------------
void gpio_mode(PIN_enum pin, GPIOMODE_enum mode)

typedef enum
{
//pnm1 pnm0
GPIO = 0, //准双向口(弱上拉)
GPO_PP = 1, //推挽输出
GPI_IMPEDANCE = 2, //高阻输入
GPI_OD = 3, //开漏输出
}GPIOMODE_enum;

关于P52 与 P5_2 的区别

P52 是在 STC32Gxx.h 这个官方的文件里定义的,实际上在调用的时候感觉是一个很强大的变量,相当于直接读取或改变相应引脚的电平。可能本质上是 *p 一类的。(本人并没有细究)

P5_2 是在逐飞自己写的头文件里定义的枚举,实际上是个定值,仅在调用逐飞的一些关于gpio的函数里用来确定引脚。

EXTI

//-------------------------------------------------------------------------------------------------------------------
// @brief 外部中断初始化
// @param NULL
// @return void
// Sample usage: exit_init(INT0_P32,BOTH) //初始化P32 作为外部中断引脚,双边沿触发。
//-------------------------------------------------------------------------------------------------------------------
void exit_init(INTN_enum int_n,INT_MODE_enum mode)

typedef enum // 枚举ADC通道
{
INT0_P32 = 0, //支持边沿,下降沿中断
INT1_P33, //支持边沿,下降沿中断
INT2_P36, //支持下降沿中断
INT3_P37, //支持下降沿中断
INT4_P30, //支持下降沿中断
}INTN_enum;

typedef enum // 枚举ADC通道
{
BOTH, //边沿
FALLING_EDGE, //下降沿
// RISING_EDGE, //不支持上升沿

}INT_MODE_enum;

示例:

main.c:

void main()
{
    board_init();            // 初始化寄存器,勿删除此句代码。
    
    // 此处编写用户代码(例如:外设初始化代码等)

    exit_init(INT0_P32, FALLING_EDGE);    //下降沿触发INT0_P32中断
                                        //触发中断LED 就会被点亮

    while(1)
    {

    }
}

isr.c:

#define LED P52
void INT0_Isr() interrupt 0
{
    LED = 0;    //点亮LED
}

PIT

pit_timer_ms(TIM_4, 1);                //使用TIMER作为周期中断,时间1ms一次
                                     //进入1000次中断 翻转一次LED,也就是1000MS 翻转一次LED

//-------------------------------------------------------------------------------------------------------------------
// @brief 定时器周期中断
// @param tim_n 定时器通道号
// @param time_ms 时间(ms)
// @return void
// Sample usage: pit_timer_ms(TIM_0, 10)
// 使用定时器0做周期中断,时间10ms一次。
//-------------------------------------------------------------------------------------------------------------------
void pit_timer_ms(TIMN_enum tim_n,uint16 time_ms)

typedef enum // 枚举ADC通道
{
TIM_0,
TIM_1,
TIM_2,
TIM_3,
TIM_4,
}TIMN_enum;

示例:

main.c:

void main()
{
    board_init();            // 初始化寄存器,勿删除此句代码。
    
    // 此处编写用户代码(例如:外设初始化代码等)

    pit_timer_ms(TIM_4, 1);                //使用TIMER作为周期中断,时间1ms一次
                                        //进入1000次中断 翻转一次LED,也就是1000MS 翻转一次LED

    while(1)
    {

    }
}

isr.c:

uint32 count = 0;
void TM4_Isr() interrupt 20
{
    TIM4_CLEAR_FLAG; //清除中断标志
    if(count++ >= 1000)
    {
        count = 0;
        LED = !LED;
    }
    
//    ccd_collect();     //CCD采集数据

}

编码器(脉冲捕获)

从逐飞的库可以看出来,stc是不能用正交式编码器的,只能用较为简单的方向式编码器通过一个脚读电平判断正反转,一个脚记录脉冲数计算转数来手动解算。读电平就用前面的gpio就行了,但是脉冲计数这事儿,因为编码器转一圈产生的脉冲数是非常可观的,你要是想用什么EXTI来手动外部中断就stc这cpu得够呛,所以我们需要用类似于DMA的一种独立的模块来计数(个人理解)。

这就用到了我们计时器的脉冲计数功能。用过stm32的可能都知道,在cube里面配置那些比较高级的定时器的时候它一般都会让我们选择是外部源还是内部源。个人理解定时器本质上就是一个计数器,当使用内部源,也就是我们一般所使用的就是内部晶振产生的源时,该定时器用于定时,数到一定的数量就计一定的时间(一个周期)。

而使用外部源时,其作为定时器的准确性是完全靠不上了,但是他就可以成为一个单纯的计数器,帮我们计算脉冲数。这也正是它可以用来为编码器计数的原因。

值得注意的是,既然我们这个定时器的计数功能给了外部脉冲,那么他就不能通过计数内部脉冲来作为定时器了。换句话讲,就是一个编码器就会占用一个定时器,每个定时器同一时间都只能以一种工作方式工作。(不过stc的pwm不是用定时器产生的不用考虑干扰)。

而stc的定时器本来就不多,tim2又分配给串口做波特率发生器了,所以大家要合理分配定时器资源。

关于具体的使用,直接看例程叭。

#define DIR P35
int16 dat = 0;
void main()
{
    board_init();            // 初始化寄存器,勿删除此句代码。
    
    // 此处编写用户代码(例如:外设初始化代码等)
    
    ctimer_count_init(CTIM0_P34);
    
    while(1)
    {
        if(DIR == 1)
        {
            dat = ctimer_count_read(CTIM0_P34);
        }
        else
        {
            dat = ctimer_count_read(CTIM0_P34) * -1;
        }
        ctimer_count_clean(CTIM0_P34);
        printf("dat = %d\r\n", dat);
        delay_ms(100);
    }
}

//-------------------------------------------------------------------------------------------------------------------
// @brief 定时器初始化作为外部计数
// @param tim_n 选择模块
// @return void
// @since v1.0
// Sample usage: ctimer_count_init(CTIM0_P34); //初始化定时器0,外部输入为P3.4引脚
// @note 串口1使用定时器1作为波特率发生器,
// 串口2使用定时器2作为波特率发生器,
// 串口3使用定时器3作为波特率发生器,
// 串口4使用定时器4作为波特率发生器,
// STC16F仅有定时器0-定时器4,这5个定时器。
// 编码器采集数据也需要定时器作为外部计数。
//-------------------------------------------------------------------------------------------------------------------
void ctimer_count_init(CTIMN_enum tim_n)

//-------------------------------------------------------------------------------------------------------------------
// @brief 获取计数数值
// @param countch 计数通道号及引脚
// @return uint32 返回计数值
// Sample usage: num = ctimer_count_read(CTIM0_P34);
//-------------------------------------------------------------------------------------------------------------------
uint16 ctimer_count_read(CTIMN_enum tim_n)

//-------------------------------------------------------------------------------------------------------------------
// @brief 清除计数数值
// @param countch 计数通道号及引脚
// @return void
// Sample usage: ctimer_count_clean(CTIM0_P34);
//-------------------------------------------------------------------------------------------------------------------
void ctimer_count_clean(CTIMN_enum tim_n)

typedef enum // 枚举ADC通道
{
CTIM0_P34=0,
CTIM1_P35,
CTIM2_P12,
CTIM3_P04,
CTIM4_P06,
}CTIMN_enum;

ADC

初始化

adc_init(ADC_P10, ADC_SYSclk_DIV_2); //初始化ADC,P1.0通道 ,ADC时钟频率:SYSclk/2

//-------------------------------------------------------------------------------------------------------------------
// @brief ADC初始化
// @param adcn 选择ADC通道
// @param speed ADC时钟频率
// @return void
// Sample usage: adc_init(ADC_P10,ADC_SYSclk_DIV_2);//初始化P1.0为ADC功能,ADC时钟频率:SYSclk/2
//-------------------------------------------------------------------------------------------------------------------
void adc_init(ADCN_enum adcn,ADC_SPEED_enum speed)

typedef enum
{
ADC_P10 = 0 ,
ADC_P11 ,
ADC_P12 , //STC16F没有这个引脚,仅做站位使用
ADC_P13 ,
ADC_P14 ,
ADC_P15 ,
ADC_P16 ,
ADC_P17 ,

 ADC_P00         , 
 ADC_P01         , 
 ADC_P02            , 
 ADC_P03            , 
 ADC_P04            , 
 ADC_P05            , 
 ADC_P06            , 
 ADC_POWR = 0x0f    , //内部AD 1.19V

} ADCN_enum;

typedef enum
{
ADC_SYSclk_DIV_2 = 0,
ADC_SYSclk_DIV_4,
ADC_SYSclk_DIV_6,
ADC_SYSclk_DIV_8,
ADC_SYSclk_DIV_10,
ADC_SYSclk_DIV_12,
ADC_SYSclk_DIV_14,
ADC_SYSclk_DIV_16,
ADC_SYSclk_DIV_18,
ADC_SYSclk_DIV_20,
ADC_SYSclk_DIV_22,
ADC_SYSclk_DIV_24,
ADC_SYSclk_DIV_26,
ADC_SYSclk_DIV_28,
ADC_SYSclk_DIV_30,
ADC_SYSclk_DIV_32,
} ADC_SPEED_enum;

调用读值

adc_data[0] = adc_once(ADC_P10, ADC_12BIT); //采集一次ADC,精度10位

//-------------------------------------------------------------------------------------------------------------------
// @brief ADC转换一次
// @param adcn 选择ADC通道
// @param resolution 分辨率
// @return void
// Sample usage: adc_convert(ADC_P10, ADC_10BIT);
//-------------------------------------------------------------------------------------------------------------------
uint16 adc_once(ADCN_enum adcn,ADCRES_enum resolution)

typedef enum
{
ADC_P10 = 0 ,
ADC_P11 ,
ADC_P12 , //STC16F没有这个引脚,仅做站位使用
ADC_P13 ,
ADC_P14 ,
ADC_P15 ,
ADC_P16 ,
ADC_P17 ,

 ADC_P00         , 
 ADC_P01         , 
 ADC_P02            , 
 ADC_P03            , 
 ADC_P04            , 
 ADC_P05            , 
 ADC_P06            , 
 ADC_POWR = 0x0f    , //内部AD 1.19V

} ADCN_enum;

typedef enum // 枚举ADC通道
{

ADC_12BIT=0,    //12位分辨率
 ADC_11BIT,        //11位分辨率
 ADC_10BIT,        //10位分辨率
 ADC_9BIT,        //9位分辨率
 ADC_8BIT,         //8位分辨率

}ADCRES_enum;

示例:

uint16 adc_data[3];
void main()
{
    board_init();            // 初始化寄存器,勿删除此句代码。
    
    // 此处编写用户代码(例如:外设初始化代码等)
    
    adc_init(ADC_P10, ADC_SYSclk_DIV_2);    
    //初始化ADC,P1.0通道 ,ADC时钟频率:SYSclk/2

    adc_init(ADC_P11, ADC_SYSclk_DIV_2);    
    //初始化ADC,P1.1通道 ,ADC时钟频率:SYSclk/2

    adc_init(ADC_P13, ADC_SYSclk_DIV_2);    
    //初始化ADC,P1.2通道 ,ADC时钟频率:SYSclk/2

    while(1)
    {
        //使用在线调试,查看adc_data数组的数值,可以得到AD数据。
        adc_data[0] = adc_once(ADC_P10, ADC_12BIT);    //采集一次ADC,精度10位
        adc_data[1] = adc_once(ADC_P11, ADC_10BIT);    //采集一次ADC,精度9位
        adc_data[2] = adc_once(ADC_P13, ADC_8BIT);    //采集一次ADC,精度8位
        printf("adc_data[0] = %d\r\n", adc_data[0]);
        printf("adc_data[1] = %d\r\n", adc_data[1]);
        printf("adc_data[2] = %d\r\n", adc_data[2]);
        
        delay_ms(100);
    }
}

PWM

初始化

pwm_init(PWMB_CH2_P01, 17000, 0);

//初始化PWMB_CH2_P01 输出PWM频率17000HZ 占空比为百分之 pwm_duty / PWM_DUTY_MAX * 100

//-------------------------------------------------------------------------------------------------------------------
// @brief PWM初始化
// @param pwmch PWM通道号及引脚
// @param freq PWM频率(10Hz-3MHz)
// @param duty PWM占空比
// @return void
// Sample usage:
// pwm_init(PWM0_P00, 100, 5000); //初始化PWM0 使用引脚P0.0 输出PWM频率100HZ 占空比为百分之 5000/PWM_DUTY_MAX*100
// PWM_DUTY_MAX在zf_pwm.h文件中 默认为10000
//-------------------------------------------------------------------------------------------------------------------
void pwm_init(PWMCH_enum pwmch,uint32 freq, uint32 duty)

typedef enum
{
//PWMA和PWMB是两组不同的PWM

 //以下是PWMA通道。
 //同一组PWM,同一时刻,只能有同一个PWM输出。
 //例如:PWMA_CH1P_P10 和 PWMA_CH1N_P11不能一起输出。
 PWMA_CH1P_P10 = 0x00,PWMA_CH1N_P11,
 PWMA_CH1P_P20,         PWMA_CH1N_P21,
 PWMA_CH1P_P60,         PWMA_CH1N_P61,

PWMA_CH2P_P12 = 0x10,//该引脚已做 USB 内核电源稳压脚
 PWMA_CH2N_P13,          
 PWMA_CH2P_P22,         PWMA_CH2N_P23,
 PWMA_CH2P_P62,         PWMA_CH2N_P63,

PWMA_CH3P_P14 = 0x20,PWMA_CH3N_P15,
 PWMA_CH3P_P24,         PWMA_CH3N_P25,
 PWMA_CH3P_P64,         PWMA_CH3N_P65,

PWMA_CH4P_P16 = 0x30,PWMA_CH4N_P17,
 PWMA_CH4P_P26,         PWMA_CH4N_P27,
 PWMA_CH4P_P66,         PWMA_CH4N_P67,
 PWMA_CH4P_P34,         PWMA_CH4N_P33,
 
 //以下是PWMB通道。
 //同一组PWM,同一时刻,只能有同一个PWM输出。
 //例如:PWMB_CH1_P20 和 PWMB_CH1_P17 不能同时输出 
 //但是不同的通道可以同一时刻输出。
 //例如:PWMB_CH1_P20 和 PWMB_CH2_P21可以同时输出
 PWMB_CH1_P20 = 0x40,
 PWMB_CH1_P17,
 PWMB_CH1_P00,
 PWMB_CH1_P74,

PWMB_CH2_P21 = 0x50,
 PWMB_CH2_P54,        //该引脚为复位引脚
 PWMB_CH2_P01,
 PWMB_CH2_P75,

PWMB_CH3_P22 = 0x60,
 PWMB_CH3_P33,
 PWMB_CH3_P02,
 PWMB_CH3_P76,

PWMB_CH4_P23 = 0x70,
 PWMB_CH4_P34,
 PWMB_CH4_P03,
 PWMB_CH4_P77,

}PWMCH_enum;

改变占空比

//-------------------------------------------------------------------------------------------------------------------
// @brief PWM占空比设置
// @param pwmch PWM通道号及引脚
// @param duty PWM占空比
// @return void
// Sample usage: pwm_duty(PWM0_P00, 5000); //初始化PWM0 使用引脚P0.0 输出PWM频率50HZ 占空比为百分之 5000/PWM_DUTY_MAX*100
// PWM_DUTY_MAX在fsl_pwm.h文件中 默认为10000
//-------------------------------------------------------------------------------------------------------------------
void pwm_duty(PWMCH_enum pwmch, uint32 duty)

逐飞给的pwm示例看着很神奇,就不引用了

结尾

懂这几个就差不多够用了,看数据直接用 printf + vofa 就行,逐飞都给你配好了

就写到这儿叭。

标签: 学习 单片机

本文转载自: https://blog.csdn.net/2301_77916560/article/details/139186624
版权归原作者 吗喽是这样打的吗 所有, 如有侵权,请联系我们删除。

“逐飞科技STC32G12K128开源库学习(基础)”的评论:

还没有评论