/*
-----------------------------------------------------------------------------------------
工程:
Test系列工程
环境:
AVR Studio4.17 + WinAVR2010
设备:
Atmega16
作者:
遥远的海
日期:
2015-08-01
说明:
输入捕获之电机测速 PWM电机调速
PD6 输入捕获,用来测量电机转速
PD7 启动、停止电机(低电平电机转动,高电平电机停转)
-----------------------------------------------------------------------------------------
*/
//---------------------------
//数据类型
//---------------------------
typedef unsigned char U8;
typedef signed char S8;
typedef unsigned int U16;
typedef signed int S16;
typedef unsigned long U32;
//---------------------------
//电机控制IO 占用PD7(21)脚
//---------------------------
#define MOTO_BIT 0x80
#define MOTO_Init() DDRD |= MOTO_BIT //配置 PD7 口为输出
//---------------------------
//总中断
//---------------------------
#define EN_INT() sei() //开中断
#define DS_INT() cli() //关中断
//串口发送标志
volatile U8 m_ucFlag=0;
//输入捕获时间印记
volatile U32 m_ulICR=0;
/*
-----------------------------------------------------------------------------------------
马达初始化函数
PD6 输入捕获,用来测量电机转速
PD7 OC2,T/C2 PWM 输出(低电平电机转动,高电平电机停转)
使用28线测速码盘
-----------------------------------------------------------------------------------------
*/
void Moto_Init(void)
{
//--------------------------------------
//T/C2 PWM ,转速控制
//--------------------------------------
//要想在引脚上得到输出信号必须将 OC2 的数据方向设置为输出
//配置 PD7 口为输出
MOTO_Init();
TCCR2=0;
//16MHz 时钟32分频(2us)
//8位计数器最大计数周期=255*2us 约为0.5ms
//因为相位PWM频率是计数器溢出频率0.5倍
//所以相位PWM模式下,PWM频率约为1KHz。
TCCR2 |= (0<
//波形产生模式:相位PWM
TCCR2 |= (0<
//比较输出模式:
//在升序计数时发生比较匹配将置位OC2 ;
//降序计数时发生比较匹配将清零OC2。
//我的电机控制口低电平转动
TCCR2 |= (1<
//可以通过调节OCR2值来调节占空比。
//初始占空比128/255=50%(对我来说其实是空占比 OCR2/255)。
OCR2=128;
//--------------------------------------
//T/C1 输入捕获,电机测速
//--------------------------------------
//PD6 (ICP1 单片机第20脚) 配置为输入
DDRD &=~(1<
//PD6 上拉电阻
PORTD|= (1<
//Bit 7 – ICNC1: 入捕捉噪声抑制器
//Bit 6 – ICES1: 输入捕捉触发沿选择 0下降沿触发,1上升沿触发
//Bit 2:0 – CS1 2:0: 时钟选择
//使能输入捕获噪声抑制
//初始设置为下降沿触发
//时钟分频 8 (16M外部时钟下0.5微秒计数一次)
TCCR1B|=0B10000010;
//T/C1 输入捕捉中断使能
TIMSK|= 1<
}
/*
-----------------------------------------------------------------------------------------
定时器1输入捕获中断,计数周期0.5微秒。
TCCR1B&=~0x40; 下降沿触发
TCCR1B|=0x40; 上升沿触发
我的电机测速码盘是 28线,精度不高,因此测量一周计数时间。
-----------------------------------------------------------------------------------------
*/
ISR(SIG_INPUT_CAPTURE1)
{
static U8 ucStep;
U16 usICR;
//保存时间印记
usICR=ICR1;
//清零计数器
TCNT1 = 0;
switch(ucStep)
{
//第1个下降沿
case 0:
m_ulICR=0;
ucStep++;
break;
//第29个下降沿,整好转一周
case 28:
m_ulICR+=usICR;
//串口发送标志
m_ucFlag=1;
ucStep=0;
break;
default:
m_ulICR+=usICR;
ucStep++;
break;
}
return;
}
/*
-----------------------------------------------------------------------------------------
USART
-----------------------------------------------------------------------------------------
*/
#define UART_BUF_LEN 5 //串口发送缓存长度
#define UART_TIME_OUT 500 //超时控制
//串口发送缓存
static U8 m_SndBuf[UART_BUF_LEN];
static U8 *pSnd;
static U8 *pSnE; //发送缓存尾部
/*
-----------------------------------------------------------------------------------------
USART发送完中断,每发送完一个字符产生一次中断
-----------------------------------------------------------------------------------------
*/
ISR(SIG_UART_TRANS)
{
if(pSnd
{
UDR=*pSnd++;
}
else
pSnd=m_SndBuf;
}
/*
-----------------------------------------------------------------------------------------
串口初始化
115200 8 N 1
-----------------------------------------------------------------------------------------
*/
void UART_Init(void)
{
pSnd=m_SndBuf;
pSnE=pSnd+UART_BUF_LEN;
DDRD|=(1<
//先关闭串口所有收发功能
UCSRB=0x00;
UCSRA=0x00;
//帧格式 8 N 1
UCSRC= (1<
//波特率设置 fosc = 16.0000 MHz,115200 ,UBRR=8
UBRRH=0x00;
UBRRL=0x08;
//使能管脚串口功能,使能发送中断
UCSRB=(1<
}
/*
-----------------------------------------------------------------------------------------
发送数据,将数据缓存 m_SndBuf[]中 pSnd到pSnE之间的数据发送出去
-----------------------------------------------------------------------------------------
*/
void UART_Write(void)
{
U16 timeOut=UART_TIME_OUT;
//等待发送完成
while(!(UCSRA&(1<
{
//超时控制
if(--timeOut==0)
return ;
}
//将数据发送出去
UDR=*pSnd++;
}
/*
-----------------------------------------------------------------------------------------
函数:
main
功能:
C 语言主函数
入口:
void
出口:
int
备注:
电机每秒转速==1000000(us)/(m_ulICR*0.5(us))==2000000(us)/(m_ulICR))
电机每分钟转速==120000000/m_ulICR
-----------------------------------------------------------------------------------------
*/
int main(void)
{
U16 usSpeed=0;
float fSpeed=0;
Moto_Init();
UART_Init();
EN_INT(); //开全局中断
while(1)
{
if(m_ucFlag)
{
//计算电机每分钟转速
fSpeed=(float)(120000000/(m_ulICR));
usSpeed=(U16)(fSpeed);
//发送数据到串口
m_SndBuf[0]=0xF5;
m_SndBuf[1]=(U8)usSpeed;
m_SndBuf[2]=(U8)(usSpeed>>8);
m_SndBuf[3]=m_SndBuf[1]^m_SndBuf[2];
m_SndBuf[4]=0xF5;
//发送指针指向发送缓存头部
pSnd=m_SndBuf;
//数据尾指针
pSnE=pSnd+UART_BUF_LEN;
//数据将在发送中断中全部自动发送。
UART_Write();
}
m_ucFlag=0;
}
return 0;
}
“勿在浮沙筑高台”
遥远的海
(待续)