STM8 TIM1 测试外部信号频率
时间:10-02
整理:3721RD
点击:
亲自测试通过 所用硬件电路 数码管共阴, IO口 PB PD PC 口
信号输出口PE0 信号采集口PC1 , 或直接把测试信号 输入PC1 口 ,注意电压 啊,信号电压高的话STM8 不能承受
/* MAIN.C file
*
* Copyright (c) 2002-2005 STMicroelectronics
*/
/****
* 实现功能 利用TIM1 输入捕获功能捕获输入信号的周期占空比
*
* STM8 输入捕获功能TIM1 测量周期的原理 是 当被测量信号的边沿 (下降或上升) 到来时
* 启动定时器开始定时 等被测量信号 边沿在一次到来时 读取定时器 的计数值 从而就可以计算出来
* 第二次测量的计数值 - 第一次测量的计数值 = Y 系统晶振频率/Y = 测量到的信号的频率
*
* 被测量信号的周期 占空比类似
* STM8 捕获有4个端口 TIM1 啊
* 这个输入捕获功能有些复杂 请仔细看 所有的注释 漏掉一点 寄存器的说明就搞不懂了
* 输入捕获模式下,当检测到ICi 信号上相应的边沿后,计数器的当前值被锁存到捕获比较寄存器TIM1_CCRx 中
* TIM1_CNTRH TIM1_CNTRL 的值被锁存在 TIM1_CCR1H TIM1_CCR1L 中
* 当发生捕获事件 时 相应的 捕获中断标志位 CCiLF 标志 被置1
* //如果TIM1_IER 寄存器 CCiLE 置位 使能了中断,则产生中断事件 中断请求
* 如果发生捕获事件时 CCiLE 已经是高 那么重复捕获标志位 CCIOF TIM1_SR2 被置1
* TI1 输入的上升沿时捕获计数器的值TIM1_CCR1 寄存器中步骤如下:
* 选择有效的输入端,配置IO 口这点很重要 配置为输入口 比如PC1 也就是TIM1_CH1
* 所以写入TIM1_CCR1 寄存器总的 CC1S = 01,此时通道配置为输入 并且TIM1_CCR1 寄存器为只读
* TIM1_CCMR1 [ [ICIF[3:0] IC1PSC[1:0]] CCIS[1:0] ] 这里选择输入捕获模式
* ICIF[3:0] 配置输入捕获1 滤波器有无采样频率
* IC1PSC[1:0] 配置输入捕获1 是否需要预分频 主要是有些信号过快 或频率过高 这里设置的意思是
* 不如上升沿信号 1S 过来 10000 个, 但采集超过或小于 捕获频率 我们就 10个上升沿或 100个上升沿
* 采集计数一次 这样有稳定性和 准确性考虑。
* CC1S[1:0] 捕获比较 1选择
* 定义通道的方向及输入脚的选择 这位特别注意 你立即写 可能会没有效果
* 这位寄存器 最下 注意 :CC1S 仅在通道关闭时TIM1_CCER1 寄存器CC1E = 0 才可以写。
* 最好 TIM1_CCER1 &= 0B11111110 在写这句
*
* *****************************
* 根据输入信号TIi 特点 可通过配置TIM1_CCMRi 寄存器中的 ICiF 来设置相应输入滤波器的滤波时间
* 上面有说明这就不在写了
************************************
* 选择TI1 通道的有效转换边沿,在TIM1_CCER1 寄存器中写入 CC1P = 0 上升沿。
* TIM1_CCER1 8位 高4位 定义输入捕获2 低4位定义输入捕获1
* CC2NP CC1NP 输入捕获比较1/2 互补输出极性 =0 高电平有效 =1 低电平有效 这里没有用
* CC2NE CC1NE 输入捕获比较1/2 互补输出使能 =0 关闭 =1 开启 没有用
* CC2P CC1P CC1 或 CC2 配置为输入 = 0 捕获发生在TI1F 的高电平 =1 捕获发生在TI1F 低电平 * * 这里选择 0
* CC2E CC1E 输入捕获输出使能位 = 0 禁止捕获 =1 使能捕获
************************************
* 配置预分配 这里希望发生的每个有效电平转换都采集到 这句好好理解 如果8 分频怎么测量到输入的频率
* 8*系统频率/(第二次计数值 - 第一次计数值) = 测量到的频率
****************************************
* 如果需要中断设置 TIM1_IER 寄存器中CC1IE 允许中断 ,这里没有使用中断 下个例子使用
*
*/
#include "stm8s105c4.h"
unsigned long frequency;
unsigned char dutycycle;
unsigned int cvalue1,cvalue2;
unsigned char gewei,shiwei,baiwei,qianwei,dutycycle1,dutycycle2;
unsigned char dis[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//数码管选择共阴极 数码管
void tim1_init(void); //定时器初始化
void cco_init(void); //CCO 时钟
void gpio_init(void); //GPIO 初始化
void display(void); //显示
void delay(unsigned int t); //延时
/******************************************************************************/
//配置系统时钟
void CLK_Init(void)
{
/*
CLK_CKdivR = 0x11; // 10: fHSI = fHSI RC output/ 4
// = 16MHZ / 4 =4MHZ
// 001: fCPU=fMASTER/2. = 2MHZ
*/
CLK_ECKR |=0X1; //开启外部时钟
while(!(CLK_ECKR&0X2)); //等待外部时钟rdy
//外部晶振 = 8MHz
//CLK_CKdiv = 0XF8 1111 1000
//CLK_CKdivR &= 0X00; //CPU无分频
//CLK_CKdivR &= 0X07;
//16000000/128 = 125khz
//CLK_CKdivR = 0X00; //不分频
// 16000000 /8 = 2MHZ
CLK_CKdivR = 0X00; // 16分频
//16000.000/16 = 1MHZ
CLK_SWR = 0XB4; //选择外部时钟
while(!(CLK_SWCR&0X8)); //这里要等
CLK_SWCR |=0X02; //使能外部时钟
}
//可配置时钟输出功能 CCO
//用户可以通过配置 CCO 选择外部引脚 输出指定 时钟
//可配置时钟输出寄存器 CLK_CCOR
// CCOBSY 可配置时钟输出忙碌标志位
// CCORDY 可配置时钟输出准备就绪 =0 CCO 时钟可用 =1 CCO时钟不可用
// CCOSEL [3:0] 可配置时钟输出源选择
void cco_init(void)
{
CLK_CCOR |= 0X03; //Flsi 时钟输出
//CLK_CCOR |= 0X05; //Fhse 时钟输出
//CLK_CCOR |= 0X09; //Fcpu 时钟输出
//CLK_CCOR |= 0X15; //Fcpu/64 时钟输出
}
void delay(unsigned int t)
{
while(t--);
}
void gpio_init(void)
{
PB_ODR = 0XFF;
PB_DDR = 0XFF;
PB_CR1 = 0XFF;
PB_CR2 = 0XFF;
// PB 口 为 位选
PD_ODR = 0XFF;
PD_DDR = 0XFF;
PD_CR1 = 0XFF;
PD_CR2 = 0XFF;
//PB 口 为 段选
PE_DDR = 0X01;
PE_CR1 = 0X01;
PE_CR2 = 0X01;
PC_DDR &= 0B11111101; //配置捕获输入 IO 口
PC_CR1 |= 0B00000010; //PC1
}
void display(void)
{
qianwei = frequency/1000;
baiwei = (frequency%1000)/100;
shiwei = (frequency%100)/10;
gewei = frequency%10;
PD_ODR = dis[gewei];
PB_ODR = 0xfe; //0b11111110;
delay(10);
PD_ODR = dis[shiwei]|0x80; //为什么 与 0X80 显示小数点 用
PB_ODR = 0xfd; //0b11111101; //1111 1011
delay(10);
PD_ODR = dis[baiwei];
PB_ODR = 0xfb; //0b11111011; //1111 1101
delay(50);
PD_ODR = dis[qianwei];
PB_ODR = 0xf7; //0b111101111; //1111 1110
delay(50);
}
void tim1_init(void)
{
TIM1_CNTRH = 0X00;
TIM1_CNTRL = 0X00;
TIM1_PSCRH = 0X00;
TIM1_PSCRL = 0X00;
TIM1_CCER1 &= (unsigned char ) ~0x01;
//TIM1_CCMR1 寄存器 CC1S 写 01 将端口配置为输入 但TIM1_CCMR1 寄存器中有说明
// CC1S 更改的需要 在通道关闭 TIM1_CCER1 寄存器 CC1E=0 时才可写入
//首先对 CC1E 位置 0 之后在配置 TIM1_CCMR1;
TIM1_CCMR1 = 0X01;
// TIM1_CCMR1 中 CC1S 位=1通道配置为 输入IC1 影射到TI1FP1 上。
//无滤波功能 无预分频
//
TIM1_CCER1 &= (unsigned char)~0X02;
//TIM1_CCMR1 |= 0X0C;
//128KHZ/8=4000
TIM1_CCER1 |= 0X01;
//捕获使能
TIM1_CR1 |=0X01;
//使能定时器计数器
}
void main()
{
unsigned int i;
CLK_CKdivR = 0X00; //系统时钟不分频
gpio_init();
cco_init();
tim1_init();
CLK_Init();
while (1)
{
//TIM1_CCER1 |= 0X01;
//IC1PSC[1:0] 输入捕获1预分频
//定义预分频系数 =00 无预分频 捕获输入口上检测
//CC1 通道被配置为输入 IC1 影射到 TI1FP1 上
//TIM1_CCER1 = 0X00;
//
while(!(TIM1_SR1 & 0X02));
//等待 当通道配置 CC1 配置为输入时该位由硬件置1 有软件清0 通过读TIM1_CCR1L 清0
// = 1 计数器值已捕获至 TI1M_CCR1 在IC1 上检测到与所选极性相同的的边沿
cvalue1 = (unsigned int )TIM1_CCR1H<<8;
cvalue1 |= TIM1_CCR1L;
TIM1_SR1 &=0xfd;//0B11111101;
//等待第二次置位
while(!(TIM1_SR1 & 0X02));
// 等待
cvalue2 = (unsigned int )TIM1_CCR1H<<8;
cvalue2 |= TIM1_CCR1L;
TIM1_SR1 &=0xfd;//0B11111101;
//TIM1_CCER1 &= 0Xfe;
//上面这句注释掉 否则只能看到一次 数码管达到的频率显示
frequency = 16000000UL/(cvalue2-cvalue1);
//frequency =cvalue1;
frequency = frequency/100; //这里与显示 小数点 有关系 1000/100 = 10.0 想想是不是啊
//不在说明了
//for(i=0;i<30;i++)
display();
}
}
信号输出口PE0 信号采集口PC1 , 或直接把测试信号 输入PC1 口 ,注意电压 啊,信号电压高的话STM8 不能承受
/* MAIN.C file
*
* Copyright (c) 2002-2005 STMicroelectronics
*/
/****
* 实现功能 利用TIM1 输入捕获功能捕获输入信号的周期占空比
*
* STM8 输入捕获功能TIM1 测量周期的原理 是 当被测量信号的边沿 (下降或上升) 到来时
* 启动定时器开始定时 等被测量信号 边沿在一次到来时 读取定时器 的计数值 从而就可以计算出来
* 第二次测量的计数值 - 第一次测量的计数值 = Y 系统晶振频率/Y = 测量到的信号的频率
*
* 被测量信号的周期 占空比类似
* STM8 捕获有4个端口 TIM1 啊
* 这个输入捕获功能有些复杂 请仔细看 所有的注释 漏掉一点 寄存器的说明就搞不懂了
* 输入捕获模式下,当检测到ICi 信号上相应的边沿后,计数器的当前值被锁存到捕获比较寄存器TIM1_CCRx 中
* TIM1_CNTRH TIM1_CNTRL 的值被锁存在 TIM1_CCR1H TIM1_CCR1L 中
* 当发生捕获事件 时 相应的 捕获中断标志位 CCiLF 标志 被置1
* //如果TIM1_IER 寄存器 CCiLE 置位 使能了中断,则产生中断事件 中断请求
* 如果发生捕获事件时 CCiLE 已经是高 那么重复捕获标志位 CCIOF TIM1_SR2 被置1
* TI1 输入的上升沿时捕获计数器的值TIM1_CCR1 寄存器中步骤如下:
* 选择有效的输入端,配置IO 口这点很重要 配置为输入口 比如PC1 也就是TIM1_CH1
* 所以写入TIM1_CCR1 寄存器总的 CC1S = 01,此时通道配置为输入 并且TIM1_CCR1 寄存器为只读
* TIM1_CCMR1 [ [ICIF[3:0] IC1PSC[1:0]] CCIS[1:0] ] 这里选择输入捕获模式
* ICIF[3:0] 配置输入捕获1 滤波器有无采样频率
* IC1PSC[1:0] 配置输入捕获1 是否需要预分频 主要是有些信号过快 或频率过高 这里设置的意思是
* 不如上升沿信号 1S 过来 10000 个, 但采集超过或小于 捕获频率 我们就 10个上升沿或 100个上升沿
* 采集计数一次 这样有稳定性和 准确性考虑。
* CC1S[1:0] 捕获比较 1选择
* 定义通道的方向及输入脚的选择 这位特别注意 你立即写 可能会没有效果
* 这位寄存器 最下 注意 :CC1S 仅在通道关闭时TIM1_CCER1 寄存器CC1E = 0 才可以写。
* 最好 TIM1_CCER1 &= 0B11111110 在写这句
*
* *****************************
* 根据输入信号TIi 特点 可通过配置TIM1_CCMRi 寄存器中的 ICiF 来设置相应输入滤波器的滤波时间
* 上面有说明这就不在写了
************************************
* 选择TI1 通道的有效转换边沿,在TIM1_CCER1 寄存器中写入 CC1P = 0 上升沿。
* TIM1_CCER1 8位 高4位 定义输入捕获2 低4位定义输入捕获1
* CC2NP CC1NP 输入捕获比较1/2 互补输出极性 =0 高电平有效 =1 低电平有效 这里没有用
* CC2NE CC1NE 输入捕获比较1/2 互补输出使能 =0 关闭 =1 开启 没有用
* CC2P CC1P CC1 或 CC2 配置为输入 = 0 捕获发生在TI1F 的高电平 =1 捕获发生在TI1F 低电平 * * 这里选择 0
* CC2E CC1E 输入捕获输出使能位 = 0 禁止捕获 =1 使能捕获
************************************
* 配置预分配 这里希望发生的每个有效电平转换都采集到 这句好好理解 如果8 分频怎么测量到输入的频率
* 8*系统频率/(第二次计数值 - 第一次计数值) = 测量到的频率
****************************************
* 如果需要中断设置 TIM1_IER 寄存器中CC1IE 允许中断 ,这里没有使用中断 下个例子使用
*
*/
#include "stm8s105c4.h"
unsigned long frequency;
unsigned char dutycycle;
unsigned int cvalue1,cvalue2;
unsigned char gewei,shiwei,baiwei,qianwei,dutycycle1,dutycycle2;
unsigned char dis[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//数码管选择共阴极 数码管
void tim1_init(void); //定时器初始化
void cco_init(void); //CCO 时钟
void gpio_init(void); //GPIO 初始化
void display(void); //显示
void delay(unsigned int t); //延时
/******************************************************************************/
//配置系统时钟
void CLK_Init(void)
{
/*
CLK_CKdivR = 0x11; // 10: fHSI = fHSI RC output/ 4
// = 16MHZ / 4 =4MHZ
// 001: fCPU=fMASTER/2. = 2MHZ
*/
CLK_ECKR |=0X1; //开启外部时钟
while(!(CLK_ECKR&0X2)); //等待外部时钟rdy
//外部晶振 = 8MHz
//CLK_CKdiv = 0XF8 1111 1000
//CLK_CKdivR &= 0X00; //CPU无分频
//CLK_CKdivR &= 0X07;
//16000000/128 = 125khz
//CLK_CKdivR = 0X00; //不分频
// 16000000 /8 = 2MHZ
CLK_CKdivR = 0X00; // 16分频
//16000.000/16 = 1MHZ
CLK_SWR = 0XB4; //选择外部时钟
while(!(CLK_SWCR&0X8)); //这里要等
CLK_SWCR |=0X02; //使能外部时钟
}
//可配置时钟输出功能 CCO
//用户可以通过配置 CCO 选择外部引脚 输出指定 时钟
//可配置时钟输出寄存器 CLK_CCOR
// CCOBSY 可配置时钟输出忙碌标志位
// CCORDY 可配置时钟输出准备就绪 =0 CCO 时钟可用 =1 CCO时钟不可用
// CCOSEL [3:0] 可配置时钟输出源选择
void cco_init(void)
{
CLK_CCOR |= 0X03; //Flsi 时钟输出
//CLK_CCOR |= 0X05; //Fhse 时钟输出
//CLK_CCOR |= 0X09; //Fcpu 时钟输出
//CLK_CCOR |= 0X15; //Fcpu/64 时钟输出
}
void delay(unsigned int t)
{
while(t--);
}
void gpio_init(void)
{
PB_ODR = 0XFF;
PB_DDR = 0XFF;
PB_CR1 = 0XFF;
PB_CR2 = 0XFF;
// PB 口 为 位选
PD_ODR = 0XFF;
PD_DDR = 0XFF;
PD_CR1 = 0XFF;
PD_CR2 = 0XFF;
//PB 口 为 段选
PE_DDR = 0X01;
PE_CR1 = 0X01;
PE_CR2 = 0X01;
PC_DDR &= 0B11111101; //配置捕获输入 IO 口
PC_CR1 |= 0B00000010; //PC1
}
void display(void)
{
qianwei = frequency/1000;
baiwei = (frequency%1000)/100;
shiwei = (frequency%100)/10;
gewei = frequency%10;
PD_ODR = dis[gewei];
PB_ODR = 0xfe; //0b11111110;
delay(10);
PD_ODR = dis[shiwei]|0x80; //为什么 与 0X80 显示小数点 用
PB_ODR = 0xfd; //0b11111101; //1111 1011
delay(10);
PD_ODR = dis[baiwei];
PB_ODR = 0xfb; //0b11111011; //1111 1101
delay(50);
PD_ODR = dis[qianwei];
PB_ODR = 0xf7; //0b111101111; //1111 1110
delay(50);
}
void tim1_init(void)
{
TIM1_CNTRH = 0X00;
TIM1_CNTRL = 0X00;
TIM1_PSCRH = 0X00;
TIM1_PSCRL = 0X00;
TIM1_CCER1 &= (unsigned char ) ~0x01;
//TIM1_CCMR1 寄存器 CC1S 写 01 将端口配置为输入 但TIM1_CCMR1 寄存器中有说明
// CC1S 更改的需要 在通道关闭 TIM1_CCER1 寄存器 CC1E=0 时才可写入
//首先对 CC1E 位置 0 之后在配置 TIM1_CCMR1;
TIM1_CCMR1 = 0X01;
// TIM1_CCMR1 中 CC1S 位=1通道配置为 输入IC1 影射到TI1FP1 上。
//无滤波功能 无预分频
//
TIM1_CCER1 &= (unsigned char)~0X02;
//TIM1_CCMR1 |= 0X0C;
//128KHZ/8=4000
TIM1_CCER1 |= 0X01;
//捕获使能
TIM1_CR1 |=0X01;
//使能定时器计数器
}
void main()
{
unsigned int i;
CLK_CKdivR = 0X00; //系统时钟不分频
gpio_init();
cco_init();
tim1_init();
CLK_Init();
while (1)
{
//TIM1_CCER1 |= 0X01;
//IC1PSC[1:0] 输入捕获1预分频
//定义预分频系数 =00 无预分频 捕获输入口上检测
//CC1 通道被配置为输入 IC1 影射到 TI1FP1 上
//TIM1_CCER1 = 0X00;
//
while(!(TIM1_SR1 & 0X02));
//等待 当通道配置 CC1 配置为输入时该位由硬件置1 有软件清0 通过读TIM1_CCR1L 清0
// = 1 计数器值已捕获至 TI1M_CCR1 在IC1 上检测到与所选极性相同的的边沿
cvalue1 = (unsigned int )TIM1_CCR1H<<8;
cvalue1 |= TIM1_CCR1L;
TIM1_SR1 &=0xfd;//0B11111101;
//等待第二次置位
while(!(TIM1_SR1 & 0X02));
// 等待
cvalue2 = (unsigned int )TIM1_CCR1H<<8;
cvalue2 |= TIM1_CCR1L;
TIM1_SR1 &=0xfd;//0B11111101;
//TIM1_CCER1 &= 0Xfe;
//上面这句注释掉 否则只能看到一次 数码管达到的频率显示
frequency = 16000000UL/(cvalue2-cvalue1);
//frequency =cvalue1;
frequency = frequency/100; //这里与显示 小数点 有关系 1000/100 = 10.0 想想是不是啊
//不在说明了
//for(i=0;i<30;i++)
display();
}
}