这一章编写编码器程序,通过定时器连接编码器,原理和细器节这里不多说,参考代码段中的网页,有两个注意事项,一是所有网上的参考代码都没有设置第二个通道,默认没有滤波,虽然能用,但是通道2抗干扰能力差,容易造成误计数。二是volatile u8 m_bInterrupt,说明在别处(计时器)会改变这个变量,不优化,因为优化后把很重要的代码删除了,详见setData函数说明。可用5个定时TIM1、TIM3-5、TIM8,最多可连接5个编码器。
特别提示,以上测试中,CPU始终接5V电压,把开发板上的5V和3.3V短接了,约二个月时间,没有出现问题,估计能长期使用,这样就可以方便直接连接其他的5V设备了。
Encode.h
#ifndef __ENCODER__
#define __ENCODER__
extern “C” { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
#pragma diag_remark 368 // 消除 warning: #368-D: class “《unnamed》” defines no constructor to initialize the following:
#include “stm32f10x.h”
#pragma diag_default 368 // 恢复368号警告
}
#include “Timer.h”
#include “IO.h”
class Encoder : public Timer // 编码器对象从Timer继承
{
// Construction
public:
Encoder(TIM_TypeDef * pTIMx);
// Properties
public:
s32 m_nCount; // 有符号32位计数值
volatile u8 m_bInterrupt; // 读取或设置数据过程被中断
protected:
private:
// Methods
public:
s32 getData(); // 取计数
void setData(s32 nData); // 设置计数值
// Overwrite
public:
virtual void onTimer(void); // 中断
};
#endif
Encode.cpp
/**
******************************************************************************
* @file Encode.cpp
* @author Mr. Hu
* @version V1.0.0 STM32F103VET6
* @date 05/22/2019
* @brief 编码输入
* @IO
* 定时器 编码器A 编码器B
* TIM1 PE9 PE11
* TIM3 PB4 PB5
* TIM4 PB6 PB7
* TIM5 PA0 PA1
* TIM8 PC6 PC7
******************************************************************************
* @remarks
* 通过定时器连接编码器,可选TIM1、TIM2-5、TIM8共5个。在中断函数onTimer中把无符
* 号16位数扩展到有符号32位数,适用范围广。最大计数频率140KHz,对刻度360的编码器,可
* 记录转速达23400转/分。
*
* 特别注意:这个文件的编译优化级别要设置成0,不优化,因为优化程序会把setData和
* getData中的重要代码删除。设置方法是右键点击左边的文件名Encoder.cpp|Options for
* file ‘Encoder.cpp“。..|C/C++|Optimization|Level0’
*
* 参考资料
* https://blog.csdn.net/wang328452854/article/details/50579832 贴子中的TIM_ICPolarity_BothEdge未定义
* https://www.cnblogs.com/ChYQ/p/6247567.html
* 按以下参数,用两个PWM做输入,24kHz以下比较保险,计数正常 72M/3000
* http://bbs.21ic.com/icview-335440-1-1.html 和这个有出入
*/
/* Includes ------------------------------------------------------------------*/
extern ”C“ { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
#pragma diag_remark 368 // 消除 warning: #368-D: class ”《unnamed》“ defines no constructor to initialize the following:
#include ”stm32f10x_tim.h“
#pragma diag_default 368 // 恢复368号警告
}
#include ”Encoder.h“
// 取32位数的16位
#define GET16(num, i) (((s16*)&num)[i])
/**
* @date 05/22/2019
* @brief 编码器类,占用端口见前面的IO表
* @param pTIMx,定时器,可选TIM1、TIM2-5、TIM8共5个
* @retval None
*/
Encoder::Encoder(TIM_TypeDef * pTIMx)
: Timer(pTIMx)
, m_nCount(0)
, m_bInterrupt(0)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 使能复用输出,不映射端口时可以不用这一句
switch( (u32)pTIMx )
{
case (u32)TIM1:
GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE); // 把TIM1第1/2通道重映射到PC9/11。如果不映射,不要这一句
IO(GPIOE, GPIO_Pin_9 | GPIO_Pin_11, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
break;
case (u32)TIM3:
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); // 把TIM3第1/2通道重映射到P4/5,只用PC6-7。如果不映射,不要这一句
IO(GPIOB, GPIO_Pin_4 | GPIO_Pin_5, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
break;
case (u32)TIM4:
IO(GPIOB, GPIO_Pin_6 | GPIO_Pin_7, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
break;
case (u32)TIM5:
IO(GPIOA, GPIO_Pin_0 | GPIO_Pin_1, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
break;
case (u32)TIM8:
IO(GPIOC, GPIO_Pin_6 | GPIO_Pin_7, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
break;
default:
return; // ?? 异常
}
TIM_TimeBaseStructure.TIM_Period = 0xffff; // 设定计数器重装值,在中断函数中进位或借位
TIM_TimeBaseStructure.TIM_Prescaler = 0; // 时钟预分频值,好象是对输入进行分频
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 采样分频倍数1,未明该语句作用。
TIM_TimeBaseInit(m_pTIMx, &TIM_TimeBaseStructure);
// 要放到后面两个TIM_ICInit的后面
TIM_EncoderInterfaceConfig(m_pTIMx, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Falling);//下降计数,实测是4分频,即1个周期有4个计数
// 设置通道1,TIM_ICFilter=15时最高计数频率约140KHz,36000000/32/8 = 140625,详见操作手册:ETF[3:0]:外部触发滤波 (External trigger filter)
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure); // 将结构体中的内容缺省输入
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; // 通道1
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 配置输入分频,不分频, (检测到几次算一次捕获)
TIM_ICInitStructure.TIM_ICFilter = 15; // 选择输入比较滤波器,实测这个参数最有用,TIM_ClockDivision和TIM_ICPrescaler不明显,还影响计数频率,高速时可以用排线
TIM_ICInit(m_pTIMx, &TIM_ICInitStructure); // 将TIM_ICInitStructure中的指定参数初始化
// 设置通道2,这个很重要,网上的参考代码都没有这一段,虽然能用,但是通道2抗干扰能力差,造成误计数。
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; // 通道2
TIM_ICInit(m_pTIMx, &TIM_ICInitStructure); // 将TIM_ICInitStructure中的指定参数初始化
m_pTIMx-》CNT = 0; // 初始值
enableInterrupt(); // 最后开中断
}
/**
* @date 05/22/2019
* @brief 获取编码器数据,把定时器无符号16位数转化为有符号32位数,其中m_bInterrupt是重点。
* @param None
* @retval 有符号32位编码器数据
*/
s32 Encoder::getData()
{
// 中断标志清零
m_bInterrupt = 0;
// 转换成32位数
s32 v = m_nCount | m_pTIMx-》CNT;
// 这两句是重点,表面上看m_bInterrupt在上面清零,这里也是零,没有意义,优化编译也会把这两行删除,
// 但是实际上,上面赋值的计算过程中,可能产生溢出中断,执行进位或借位操作,然后继续合并高低16位,
// 造成很大的误差(65535),测试时发现正确数据应该是0xffffffff,读出是0xffff0000,推理过程是:运
// 到上一步时,m_nCount和m_pTIMx-》CNT都是零,先m_pTIMx-》CNT读入寄存器,产生下溢出中断,进入中断
// 程序onTimer,m_pTIMx-》CNT减1,并从m_nCount借位,结果是:
// m_nCount = 0xffff0000,m_pTIMx-》CNT
// 回到这段程序再取m_nCount与前面程序获取的0合并得到错误结果0xffff0000,解决问题的方法是添加中断
// 标志m_bInterrupt,先清零,在中断程序onTimer中将m_bInterrupt置1,返回前如果m_bInterrupt是1,
// 再取一次,就能返回正确的值。遗憾的是编译优化时会删除这两行程序,只能把这个文件Encode.cpp的优化
// 级别设成0,不优化,以后如再发现类似的问题,把这些代码集中到一个文件,不影响其它代码的优化。
if(m_bInterrupt)
return getData();
return v;
}
void Encoder::setData(s32 nData)
{
// 中断标志清零
m_bInterrupt = 0;
// 分别设置高16位和低16位
GET16(m_nCount, 1) = GET16(nData, 1);
m_pTIMx-》CNT = nData;
// 这两句是重点,如果执行过程中被中断,再执行一次,参看setData()中的说明
if(m_bInterrupt)
setData(nData);
}
/**
* @date 05/22/2019
* @brief 计数中断,设置高16位值
* @param None
* @retval None
*/
void Encoder::onTimer(void)
{
// 调用基类程序,清TIM中断位
Timer::onTimer();
// 设置中断标志,非常重要,参看setData()中的说明
m_bInterrupt = 1;
// 计数溢出中断,把16位无符号计数扩展到32位有符号计数
// 只修改m_nCount的高16位
if(TIM_CR1_DIR & m_pTIMx-》CR1)
GET16(m_nCount, 1)--; // 向下溢出,高16位减1
else
GET16(m_nCount, 1)++; // 向上溢出,高16位加1
}
Main.h
#ifndef __MAIN__
#define __MAIN__
extern ”C“ { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
#pragma diag_remark 368 // 消除 warning: #368-D: class ”《unnamed》“ defines no constructor to initialize the following:
#include ”stm32f10x.h“
#pragma diag_default 368 // 恢复368号警告
}
s32 m_nCPUTemperate; // CPU温度 x 100
#endif
Main.cpp
/**
******************************************************************************
* @file Main.cpp
* @author Mr. Hu
* @version V1.0.0 STM32F103VET6
* @date 05/18/2019
* @brief 程序入口
* @io
* TIM1 Encode
* TIM2 PWM
* TIM3 Encode
* TIM4 Encode
* TIM5 Encode
* TIM7 通用定时器
* TIM8 Encode
* ADC1 ADC
* DAC1
* DAC2
*
* PA0 TIM5 Encode A
* PA1 TIM5 Encode B
* PA2 PWM
* PA3 PWM
* PA4 DAC1输出,ADC1 数据4
* PA5 DAC2输出,ADC1 数据5
* PA6 ADC1 数据6
* PA7 ADC1 数据7
* PA9 板载串口
* PA10 板载串口
* PA13 板载JLINK占用
* PA14 板载JLINK占用
* PA15 板载JLINK占用
*
* PB1 板载SW2
* PB3 板载JLINK占用
* PB4 板载JLINK占用,TIM3 Encode A
* PB5 TIM3 Encode B
* PB6 TIM4 Encode A
* PB7 TIM4 Encode B
* PB8 板载CAN
* PB9 板载CAN
* PB10 板载RS485
* PB11 板载RS485
* PB13 板载LED2
* PB14 板载LED3
* PB15 板载SW3
*
* PC0-3 ADC1 数据0-3
* PC4 板载RS485
* PC5 板载RS485
* PC6 TIM8 Encode A
* PC7 TIM8 Encode B
*
* PE9 TIM8 Encode A
* PE11 TIM8 Encode B
******************************************************************************
* @remarks
*
*/
extern ”C“ { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
#pragma diag_remark 368 //消除 warning: #368-D: class ”《unnamed》“ defines no constructor to initialize the following:
#include ”stm32f10x_tim.h“
#include ”stm32f10x_dac.h“
#pragma diag_default 368 // 恢复368号警告
}
#include ”stm32f10x_adc.h“
#include ”IO.h“
#include ”Timer.h“
#include ”GeneralTimer.h“
#include ”BoardLED.h“
#include ”PWM.h“
#include ”MedianFilter.h“
#include ”AverageFilter.h“
#include ”ADDA.h“
#include ”Encoder.h“
#include ”Main.h“
/**
* @date 05/18/2019
* @brief 主入口,主循环
* 如果不正常运行,可能是栈设置不够 startup_stm32f10x_hd.s Stack_Size EQU 0x600
* @param None
* @retval None
*/
int main(void)
{
m_nCPUTemperate = 0;
SystemInit(); // 配置系统时钟为72M
GeneralTimer tim(TIM7); // 通用定时器,实际用TIM7,不占用IO,但软件仿真只有1-4,所以选2
ADDA adda; // 定时器下紧跟启动ADDA,因为转换需要时间
//adda.daDMA(tim); // DMA方式,按数据生成正弦波,使用这个功能时,注释下面的三角波代码
这一章编写编码器程序,通过定时器连接编码器,原理和细器节这里不多说,参考代码段中的网页,有两个注意事项,一是所有网上的参考代码都没有设置第二个通道,默认没有滤波,虽然能用,但是通道2抗干扰能力差,容易造成误计数。二是volatile u8 m_bInterrupt,说明在别处(计时器)会改变这个变量,不优化,因为优化后把很重要的代码删除了,详见setData函数说明。可用5个定时TIM1、TIM3-5、TIM8,最多可连接5个编码器。
特别提示,以上测试中,CPU始终接5V电压,把开发板上的5V和3.3V短接了,约二个月时间,没有出现问题,估计能长期使用,这样就可以方便直接连接其他的5V设备了。
Encode.h
#ifndef __ENCODER__
#define __ENCODER__
extern “C” { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
#pragma diag_remark 368 // 消除 warning: #368-D: class “《unnamed》” defines no constructor to initialize the following:
#include “stm32f10x.h”
#pragma diag_default 368 // 恢复368号警告
}
#include “Timer.h”
#include “IO.h”
class Encoder : public Timer // 编码器对象从Timer继承
{
// Construction
public:
Encoder(TIM_TypeDef * pTIMx);
// Properties
public:
s32 m_nCount; // 有符号32位计数值
volatile u8 m_bInterrupt; // 读取或设置数据过程被中断
protected:
private:
// Methods
public:
s32 getData(); // 取计数
void setData(s32 nData); // 设置计数值
// Overwrite
public:
virtual void onTimer(void); // 中断
};
#endif
Encode.cpp
/**
******************************************************************************
* @file Encode.cpp
* @author Mr. Hu
* @version V1.0.0 STM32F103VET6
* @date 05/22/2019
* @brief 编码输入
* @IO
* 定时器 编码器A 编码器B
* TIM1 PE9 PE11
* TIM3 PB4 PB5
* TIM4 PB6 PB7
* TIM5 PA0 PA1
* TIM8 PC6 PC7
******************************************************************************
* @remarks
* 通过定时器连接编码器,可选TIM1、TIM2-5、TIM8共5个。在中断函数onTimer中把无符
* 号16位数扩展到有符号32位数,适用范围广。最大计数频率140KHz,对刻度360的编码器,可
* 记录转速达23400转/分。
*
* 特别注意:这个文件的编译优化级别要设置成0,不优化,因为优化程序会把setData和
* getData中的重要代码删除。设置方法是右键点击左边的文件名Encoder.cpp|Options for
* file ‘Encoder.cpp“。..|C/C++|Optimization|Level0’
*
* 参考资料
* https://blog.csdn.net/wang328452854/article/details/50579832 贴子中的TIM_ICPolarity_BothEdge未定义
* https://www.cnblogs.com/ChYQ/p/6247567.html
* 按以下参数,用两个PWM做输入,24kHz以下比较保险,计数正常 72M/3000
* http://bbs.21ic.com/icview-335440-1-1.html 和这个有出入
*/
/* Includes ------------------------------------------------------------------*/
extern ”C“ { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
#pragma diag_remark 368 // 消除 warning: #368-D: class ”《unnamed》“ defines no constructor to initialize the following:
#include ”stm32f10x_tim.h“
#pragma diag_default 368 // 恢复368号警告
}
#include ”Encoder.h“
// 取32位数的16位
#define GET16(num, i) (((s16*)&num)[i])
/**
* @date 05/22/2019
* @brief 编码器类,占用端口见前面的IO表
* @param pTIMx,定时器,可选TIM1、TIM2-5、TIM8共5个
* @retval None
*/
Encoder::Encoder(TIM_TypeDef * pTIMx)
: Timer(pTIMx)
, m_nCount(0)
, m_bInterrupt(0)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 使能复用输出,不映射端口时可以不用这一句
switch( (u32)pTIMx )
{
case (u32)TIM1:
GPIO_PinRemapConfig(GPIO_FullRemap_TIM1, ENABLE); // 把TIM1第1/2通道重映射到PC9/11。如果不映射,不要这一句
IO(GPIOE, GPIO_Pin_9 | GPIO_Pin_11, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
break;
case (u32)TIM3:
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); // 把TIM3第1/2通道重映射到P4/5,只用PC6-7。如果不映射,不要这一句
IO(GPIOB, GPIO_Pin_4 | GPIO_Pin_5, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
break;
case (u32)TIM4:
IO(GPIOB, GPIO_Pin_6 | GPIO_Pin_7, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
break;
case (u32)TIM5:
IO(GPIOA, GPIO_Pin_0 | GPIO_Pin_1, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
break;
case (u32)TIM8:
IO(GPIOC, GPIO_Pin_6 | GPIO_Pin_7, GPIO_Mode_IPU, 2); // GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
break;
default:
return; // ?? 异常
}
TIM_TimeBaseStructure.TIM_Period = 0xffff; // 设定计数器重装值,在中断函数中进位或借位
TIM_TimeBaseStructure.TIM_Prescaler = 0; // 时钟预分频值,好象是对输入进行分频
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 采样分频倍数1,未明该语句作用。
TIM_TimeBaseInit(m_pTIMx, &TIM_TimeBaseStructure);
// 要放到后面两个TIM_ICInit的后面
TIM_EncoderInterfaceConfig(m_pTIMx, TIM_EncoderMode_TI12, TIM_ICPolarity_Falling, TIM_ICPolarity_Falling);//下降计数,实测是4分频,即1个周期有4个计数
// 设置通道1,TIM_ICFilter=15时最高计数频率约140KHz,36000000/32/8 = 140625,详见操作手册:ETF[3:0]:外部触发滤波 (External trigger filter)
TIM_ICInitTypeDef TIM_ICInitStructure;
TIM_ICStructInit(&TIM_ICInitStructure); // 将结构体中的内容缺省输入
TIM_ICInitStructure.TIM_Channel = TIM_Channel_1; // 通道1
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 配置输入分频,不分频, (检测到几次算一次捕获)
TIM_ICInitStructure.TIM_ICFilter = 15; // 选择输入比较滤波器,实测这个参数最有用,TIM_ClockDivision和TIM_ICPrescaler不明显,还影响计数频率,高速时可以用排线
TIM_ICInit(m_pTIMx, &TIM_ICInitStructure); // 将TIM_ICInitStructure中的指定参数初始化
// 设置通道2,这个很重要,网上的参考代码都没有这一段,虽然能用,但是通道2抗干扰能力差,造成误计数。
TIM_ICInitStructure.TIM_Channel = TIM_Channel_2; // 通道2
TIM_ICInit(m_pTIMx, &TIM_ICInitStructure); // 将TIM_ICInitStructure中的指定参数初始化
m_pTIMx-》CNT = 0; // 初始值
enableInterrupt(); // 最后开中断
}
/**
* @date 05/22/2019
* @brief 获取编码器数据,把定时器无符号16位数转化为有符号32位数,其中m_bInterrupt是重点。
* @param None
* @retval 有符号32位编码器数据
*/
s32 Encoder::getData()
{
// 中断标志清零
m_bInterrupt = 0;
// 转换成32位数
s32 v = m_nCount | m_pTIMx-》CNT;
// 这两句是重点,表面上看m_bInterrupt在上面清零,这里也是零,没有意义,优化编译也会把这两行删除,
// 但是实际上,上面赋值的计算过程中,可能产生溢出中断,执行进位或借位操作,然后继续合并高低16位,
// 造成很大的误差(65535),测试时发现正确数据应该是0xffffffff,读出是0xffff0000,推理过程是:运
// 到上一步时,m_nCount和m_pTIMx-》CNT都是零,先m_pTIMx-》CNT读入寄存器,产生下溢出中断,进入中断
// 程序onTimer,m_pTIMx-》CNT减1,并从m_nCount借位,结果是:
// m_nCount = 0xffff0000,m_pTIMx-》CNT
// 回到这段程序再取m_nCount与前面程序获取的0合并得到错误结果0xffff0000,解决问题的方法是添加中断
// 标志m_bInterrupt,先清零,在中断程序onTimer中将m_bInterrupt置1,返回前如果m_bInterrupt是1,
// 再取一次,就能返回正确的值。遗憾的是编译优化时会删除这两行程序,只能把这个文件Encode.cpp的优化
// 级别设成0,不优化,以后如再发现类似的问题,把这些代码集中到一个文件,不影响其它代码的优化。
if(m_bInterrupt)
return getData();
return v;
}
void Encoder::setData(s32 nData)
{
// 中断标志清零
m_bInterrupt = 0;
// 分别设置高16位和低16位
GET16(m_nCount, 1) = GET16(nData, 1);
m_pTIMx-》CNT = nData;
// 这两句是重点,如果执行过程中被中断,再执行一次,参看setData()中的说明
if(m_bInterrupt)
setData(nData);
}
/**
* @date 05/22/2019
* @brief 计数中断,设置高16位值
* @param None
* @retval None
*/
void Encoder::onTimer(void)
{
// 调用基类程序,清TIM中断位
Timer::onTimer();
// 设置中断标志,非常重要,参看setData()中的说明
m_bInterrupt = 1;
// 计数溢出中断,把16位无符号计数扩展到32位有符号计数
// 只修改m_nCount的高16位
if(TIM_CR1_DIR & m_pTIMx-》CR1)
GET16(m_nCount, 1)--; // 向下溢出,高16位减1
else
GET16(m_nCount, 1)++; // 向上溢出,高16位加1
}
Main.h
#ifndef __MAIN__
#define __MAIN__
extern ”C“ { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
#pragma diag_remark 368 // 消除 warning: #368-D: class ”《unnamed》“ defines no constructor to initialize the following:
#include ”stm32f10x.h“
#pragma diag_default 368 // 恢复368号警告
}
s32 m_nCPUTemperate; // CPU温度 x 100
#endif
Main.cpp
/**
******************************************************************************
* @file Main.cpp
* @author Mr. Hu
* @version V1.0.0 STM32F103VET6
* @date 05/18/2019
* @brief 程序入口
* @io
* TIM1 Encode
* TIM2 PWM
* TIM3 Encode
* TIM4 Encode
* TIM5 Encode
* TIM7 通用定时器
* TIM8 Encode
* ADC1 ADC
* DAC1
* DAC2
*
* PA0 TIM5 Encode A
* PA1 TIM5 Encode B
* PA2 PWM
* PA3 PWM
* PA4 DAC1输出,ADC1 数据4
* PA5 DAC2输出,ADC1 数据5
* PA6 ADC1 数据6
* PA7 ADC1 数据7
* PA9 板载串口
* PA10 板载串口
* PA13 板载JLINK占用
* PA14 板载JLINK占用
* PA15 板载JLINK占用
*
* PB1 板载SW2
* PB3 板载JLINK占用
* PB4 板载JLINK占用,TIM3 Encode A
* PB5 TIM3 Encode B
* PB6 TIM4 Encode A
* PB7 TIM4 Encode B
* PB8 板载CAN
* PB9 板载CAN
* PB10 板载RS485
* PB11 板载RS485
* PB13 板载LED2
* PB14 板载LED3
* PB15 板载SW3
*
* PC0-3 ADC1 数据0-3
* PC4 板载RS485
* PC5 板载RS485
* PC6 TIM8 Encode A
* PC7 TIM8 Encode B
*
* PE9 TIM8 Encode A
* PE11 TIM8 Encode B
******************************************************************************
* @remarks
*
*/
extern ”C“ { // 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
#pragma diag_remark 368 //消除 warning: #368-D: class ”《unnamed》“ defines no constructor to initialize the following:
#include ”stm32f10x_tim.h“
#include ”stm32f10x_dac.h“
#pragma diag_default 368 // 恢复368号警告
}
#include ”stm32f10x_adc.h“
#include ”IO.h“
#include ”Timer.h“
#include ”GeneralTimer.h“
#include ”BoardLED.h“
#include ”PWM.h“
#include ”MedianFilter.h“
#include ”AverageFilter.h“
#include ”ADDA.h“
#include ”Encoder.h“
#include ”Main.h“
/**
* @date 05/18/2019
* @brief 主入口,主循环
* 如果不正常运行,可能是栈设置不够 startup_stm32f10x_hd.s Stack_Size EQU 0x600
* @param None
* @retval None
*/
int main(void)
{
m_nCPUTemperate = 0;
SystemInit(); // 配置系统时钟为72M
GeneralTimer tim(TIM7); // 通用定时器,实际用TIM7,不占用IO,但软件仿真只有1-4,所以选2
ADDA adda; // 定时器下紧跟启动ADDA,因为转换需要时间
//adda.daDMA(tim); // DMA方式,按数据生成正弦波,使用这个功能时,注释下面的三角波代码
举报