前言:在学习过STM32后,现在为了打智能车,开始学习STC32。STC32相比于STM32在库函数方面会更加简洁明了,其基本内核都差不多,只是在一些引脚表述上有少许差别,下面我将列举STC32的一些例程来对熟悉这个芯片。
//-------------------------------------------------------------------------------
// @brief GPIO设置引脚上拉电阻设置
// @param pin 选择引脚(P0_0-P7_7)
// @param pull 设置上下拉电阻 NOPULL:不设置 PULLUP:上拉
// @return void
// Sample usage: gpio_pull_set(P0_0,NOPULL); // 设置P0.0引脚没有上下拉电阻
//-------------------------------------------------------------------------------
void gpio_pull_set(PIN_enum pin, PULL_enum pull);
//-------------------------------------------------------------------------------
// @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);
//-------------------------------------------------------------------------------------------------------------------
// @brief 外部中断初始化
// @param 外部中断类,相当于EXIT0
// @param BOTH//边沿
// FALLING_EDGE//下降沿
// @return void
// Sample usage: exit_init(INT0_P32,BOTH) //初始化P32 作为外部中断引脚,双边沿触发。
//-------------------------------------------------------------------------------------------------------------------
void exit_init(INTN_enum int_n,INT_MODE_enum mode)
其中INT为stc单片机的外部中断引脚,有INT0123。配置外部中断函数在函数Isr.c里面写。
void INT0_Isr() interrupt 0
{
LED = 0; //点亮LED
}
其中的interrupt 0为INT0对应的中断源,用这个代表中断函数是INT0中断引脚对应的中断函数。
以下是各个中断引脚对应的中断源。
void INT0_Isr() interrupt 0
void INT1_Isr() interrupt 2
void INT2_Isr() interrupt 10
void INT3_Isr() interrupt 11
void INT4_Isr() interrupt 16
//-----------------------------------------------------------------------------------------
// @brief 定时器周期中断
// @param tim_n 定时器通道号,有TIM_01234
// @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);
//---------------------------------------------------------------------------------------
// @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);
定时器的中断一般就用到这个函数。对应的中断函数也有中断源与之对应。
void TM0_Isr() interrupt 1
void TM1_Isr() interrupt 3
void TM2_Isr() interrupt 12
void TM3_Isr() interrupt 19
void TM4_Isr() interrupt 20
//-----------------------------------------------------------------------------------------
// @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);
例:adc_init(ADC_P10, ADC_SYSclk_DIV_2); //初始化ADC,P1.0通道 ,ADC时钟频率:SYSclk/2
//-----------------------------------------------------------------------------------------
// @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);
例:adc_once(ADC_P10, ADC_12BIT); //采集一次ADC,精度10位
//-----------------------------------------------------------------------------------------
// @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)
例:pwm_init(PWMA_CH1P_P60, 10000, 0); //初始化PWMA 使用引脚P6.0 输出PWM频率10000HZ
//占空比为百分之 pwm_duty / PWM_DUTY_MAX * 100,这里先给0,之后有函数可以改占空比
//-------------------------------------------------------------------------------------------------------------------
// @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_duty(PWM0_P00, 5000); //初始化PWM0 使用引脚P0.0 输出
//-------------------------------------------------------------------------------------------------------------------
// @brief PWM频率设置
// @param pwmch PWM通道号及引脚
// @param freq PWM频率(10Hz-3MHz)
// @param duty PWM占空比
// @return void
// Sample usage: pwm_freq(PWM0_P00, 50, 5000); //修改化PWM0 使用引脚P0.0 输出PWM频率50HZ 占空比为百分之 5000/PWM_DUTY_MAX*100
//-------------------------------------------------------------------------------------------------------------------
void pwm_freq(PWMCH_enum pwmch, uint32 freq, uint32 duty);
例:pwm_freq(PWM0_P00, 50, 5000); //修改化PWM0 使用引脚P0.0 注意这边参数还有占空比
stc单片机的PWM输出十分的精简,不需要设置重装载值之类的参数,可以直接填入占空比与对应的输出引脚,不需要写什么输出比较函数。
//---------------------------------------------------------------------------------------
// @brief 串口初始化
// @param uart_n 串口模块号(USART_1,USART_2,USART_3,USART_4)
// @param uart_rx_pin 串口接收引脚
// @param uart_tx_pin 串口发送引脚
// @param baud 串口波特率
// @param tim_n 使用tim_n作为串口波特率发生器(TIM1-TIM4)
// @return NULL
// Sample usage: uart_init(UART_1, UART1_RX_P30, UART1_TX_P31, 115200, TIM_2); //初始化串口1 波特率115200 发送引脚使用P31 接收引脚使用P30 ,使用定时器2作为波特率发生器
// @note 串口1使用 定时器1或者定时器2 作为波特率发生器。
// 串口2使用 定时器2 作为波特率发生器。
// 串口3使用 定时器3或者定时器2 作为波特率发生器。
// 串口4使用 定时器4或者定时器2 作为波特率发生器。
// STC32G仅有 定时器0-定时器4,这5个定时器。
// 编码器采集数据也需要定时器作为外部计数。
// 如果不同的串口,使用同一个定时器,串口的波特率以最后一个初始化为准
//-----------------------------------------------------------------------------------------
void uart_init(UARTN_enum uart_n, UARTPIN_enum uart_rx_pin, UARTPIN_enum uart_tx_pin, uint32 baud, TIMN_enum tim_n);
//---------------------------------------------------------------------------------------
// @brief 串口字节输出
// @param uart_n 串口模块号(USART_1,USART_2,USART_3,USART_4)
// @param dat 需要发送的字节
// @return void
// Sample usage: uart_putchar(UART_1,0xA5); // 串口1发送0xA5
//---------------------------------------------------------------------------------------
void uart_putchar(UARTN_enum uart_n,uint8 dat);
//---------------------------------------------------------------------------------------
// @brief 串口发送字符串
// @param uart_n 串口模块号(USART_1,USART_2,USART_3,USART_4)
// @param *str 要发送的字符串地址
// @return void
// Sample usage: uart_putstr(UART_1,"i lvoe you");
//---------------------------------------------------------------------------------------
void uart_putstr(UARTN_enum uart_n,uint8 *str);
去库函数里面找
#include "SEEKFREE_18TFT.h"
#include "SEEKFREE_18TFT.c"
这里面有驱动函数
//定义脉冲引脚
#define SPEEDL_PLUSE CTIM0_P34
#define SPEEDR_PLUSE CTIM3_P04
//定义方向引脚
#define SPEEDL_DIR P35
#define SPEEDR_DIR P53
int16 templ_pluse = 0;
int16 tempr_pluse = 0;
void main()
{
WTST = 0; //设置程序代码等待参数,赋值为0可将CPU执行程序的速度设置为最快
DisableGlobalIRQ(); //关闭总中断
//sys_clk可选值:35000000,30000000, 27000000. 24000000, 22118400, 20000000, 18432000, 12000000, 11059200, 6000000, 5529600。
//设置系统频率,此频率需要跟STC-ISP软件中的 <输入用户程序运行的IRC频率>选项的频率一致。
//如果频率设置不对,将会导致串口的数据不正常,PWM的工作不正常等等。
sys_clk = 35000000; //设置系统频率为35MHz
board_init(); //初始化
ctimer_count_init(SPEEDL_PLUSE); //初始化定时器0作为外部计数
ctimer_count_init(SPEEDR_PLUSE); //初始化定时器3作为外部计数
// lcd_init(); //1.8寸TFT初始化
ips114_init(); //初始化1.14寸IPS屏幕
// oled_init_spi(); //OLED初始化
EnableGlobalIRQ(); //开启总中断
while(1)
{
//读取采集到的编码器脉冲数
templ_pluse = ctimer_count_read(SPEEDL_PLUSE);
tempr_pluse = ctimer_count_read(SPEEDR_PLUSE);
//计数器清零
ctimer_count_clean(SPEEDL_PLUSE);
ctimer_count_clean(SPEEDR_PLUSE);
//采集方向信息
if(1 == SPEEDL_DIR)
{
templ_pluse = -templ_pluse;
}
else
{
templ_pluse = templ_pluse;
}
if(1 == SPEEDR_DIR)
{
tempr_pluse = -tempr_pluse;
}
else
{
tempr_pluse = tempr_pluse;
}
//在TFT上显示,需要初始化1.8寸TFT屏幕,才能使用。
// lcd_showstr(0, 0, "pluse_l ="); lcd_showint16(8*10, 0, templ_pluse);
// lcd_showstr(0, 1, "pluse_r ="); lcd_showint16(8*10, 1, tempr_pluse);
//在1.14IPS屏幕上显示,需要初始化1.14寸ips屏幕,才能使用。
ips114_showstr(0, 0, "pluse_l ="); ips114_showint16(8*10, 0, templ_pluse);
ips114_showstr(0, 1, "pluse_r ="); ips114_showint16(8*10, 1, tempr_pluse);
//在OLED屏幕上显示,需要初始化OLED屏幕,才能使用。
// oled_p6x8str_spi(0, 0, "pluse_l ="); oled_int16_spi(8*10, 0, templ_pluse);
// oled_p6x8str_spi(0, 1, "pluse_r ="); oled_int16_spi(8*10, 1, tempr_pluse);
//延时100ms
delay_ms(100);
}
}
有库函数用,加速度角速度可以直接读取
#include "SEEKFREE_IMU660RA.h"
#include "SEEKFREE_IMU660RA.c"
例程
#include "headfile.h"
/*
* 系统频率,可查看board.h中的 FOSC 宏定义修改。
* board.h文件中FOSC的值设置为0,则程序自动设置系统频率为33.1776MHZ
* 在board_init中,已经将P54引脚设置为复位
* 如果需要使用P54引脚,可以在board.c文件中的board_init()函数中删除SET_P54_RESRT即可
*/
void main()
{
board_init(); // 初始化寄存器,勿删除此句代码。
// 此处编写用户代码(例如:外设初始化代码等)
lcd_init(); //1.8寸TFT初始化
// ips114_init(); //初始化1.14寸IPS屏幕
// oled_init_spi(); //OLED初始化
// if(imu660ra_init() == 0) //六轴陀螺仪初始化
// {
// delay_ms(500);
// printf("imu660ra init try again.\r\n");
// lcd_showstr(0,6,"OK");
// }
imu660ra_init();
pit_timer_ms(TIM_0, 10);
while(1)
{
imu660ra_get_acc(); //获取加速度数据
imu660ra_get_gyro(); //获取陀螺仪数据
//在TFT上显示,需要初始化1.8寸TFT屏幕,才能使用。
lcd_showstr(0, 0, "acc.x=");
lcd_showstr(0, 1, "acc.y=");
lcd_showstr(0, 2, "acc.z=");
lcd_showstr(0, 3, "gyro.x=");
lcd_showstr(0, 4, "gyro.y=");
lcd_showstr(0, 5, "gyro.z=");
lcd_showint16(6*10, 0, imu660ra_acc_x);
lcd_showint16(6*10, 1, imu660ra_acc_y);
lcd_showint16(6*10, 2, imu660ra_acc_z);
lcd_showint16(6*10, 3, imu660ra_gyro_x);
lcd_showint16(6*10, 4, imu660ra_gyro_y);
lcd_showint16(6*10, 5, imu660ra_gyro_z);
printf("acc.z=%d\r\n", imu660ra_acc_z);
delay_ms(100);
}
}
(4)舵机
#include "headfile.h"
uint16 duty;
void main()
{
board_init(); // 初始化寄存器,勿删除此句代码。
// 此处编写用户代码(例如:外设初始化代码等)
//pwm初始化频率为50hz 舵机居中
duty = 1.5*10000/20;
pwm_init(PWMB_CH1_P74, 50, duty);
while(1)
{
//计算舵机位置舵机位置 (0.5ms - 2.5ms)ms/20ms * 10000(1000是PWM的满占空比时候的值)
//舵机最小值为250, 最大值为1250。
//修改duty的值,可以修改舵机最大最小值。
//例:将PWM_DUTY_MAX设置为1000,则舵机最小值为25,最大值为125。
//PWM_DUTY_MAX的值在zf_pwm.h的文件中定义。
duty++;
if(1250 < duty) duty = 250;
//控制舵机达到指定位置
pwm_duty(PWMB_CH1_P74, duty);
if(250 == duty) delay_ms(1000); //当从1250的位置 回转到250的位置时 应该使用较长的延时等到舵机达到指定位置
else delay_ms(5);
}
}
(5)逐飞的无线模块
记得打USB模块的驱动
#include "headfile.h"
#define LED P52
/*
*关于内核频率的设定,可以查看board.h文件
*在board_init中,已经将P54引脚设置为复位
*如果需要使用P54引脚,可以在board.c文件中的board_init()函数中删除SET_P54_RESRT即可
*/
uint8 send_buf[] = {0x11, 0x22, 0x33};
uint8 read_buf[10];
uint32 dat_len = 0;
uint8 test_str[] = "seekfree.taobao.com\n";
void main()
{
WTST = 0; //设置程序代码等待参数,赋值为0可将CPU执行程序的速度设置为最快
DisableGlobalIRQ(); //关闭总中断
//sys_clk可选值:35000000,30000000, 27000000. 24000000, 22118400, 20000000, 18432000, 12000000, 11059200, 6000000, 5529600。
//设置系统频率,此频率需要跟STC-ISP软件中的 <输入用户程序运行时的IRC频率>选项的频率一致。
//如果频率设置不对,将会导致串口的数据不正常,PWM的工作不正常等等。
//设置系统频率,此频率需要跟STC-ISP软件中的 <输入用户程序运行时的IRC频率>选项的频率一致。
sys_clk = 35000000; //设置系统频率为35MHz
//设置系统频率,此频率需要跟STC-ISP软件中的 <输入用户程序运行时的IRC频率>选项的频率一致。
board_init(); //初始化
//无线转串口模块相关引脚定义在 wireless.h文件中
wireless_uart_init();
EnableGlobalIRQ(); //开启总中断
// STC禁止在中断里面发送数据。如果在中断里发送数据就会卡死。
// STC禁止在中断里面发送数据。如果在中断里发送数据就会卡死。
// STC禁止在中断里面发送数据。如果在中断里发送数据就会卡死。
// 发送buf
wireless_uart_send_buff(test_str, sizeof(test_str)-1);
while(1)
{
// 翻转LED
LED = !LED;
// 读取fifo中的内容
dat_len = wireless_uart_read_buff(read_buf, 10);
// 如果读取到数据
if(dat_len != 0)
{
// 将读取到的fifo发送出去
wireless_uart_send_buff(read_buf, (uint16)dat_len);
}
delay_ms(500);
}
}