8254三路计数的程序

2020-02-02 09:30发布

C语言功底不好,希望大家帮忙优化

另外,把整体的初始化程序分成3个写,出现第二个或第三个计数器高低位读反的情况,这是为什么?

8254.rar (240.75 KB, 下载次数: 6) 2012-4-3 10:12 上传 点击文件名下载附件

用于小车车速计数使用的

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
L8254.H

/*
说明:
主函数中定义
volatile long int num_8254_0,num_8254_1,num_8254_2;
volatile long int speed_count_0,speed_count_1,speed_count_2;
然后包含8254.h和8254.c

首先初始化
void counter_8254_init(void);

就可以直接引用
void counter_8254_read(void);

num_8254_N输出的对应计数器的计数值(从初始化到中断这段时间内)

speed_result(void);

输出的speed_count_N就是编码器转数(如果不需要,则直接使用counter_8254_read)

接线:
12接地 24VCC
引脚1到8 即D7-0接PORTB7-0
23WR接PORTA_PA0
22RD接PORTA_PA1
21CS接PORTA_PA2
20A1接PORTA_PA3
19A0接PORTA_PA4

11GT0接 PORTA_PA5
14GT1接 PORTA_PA6
16GT2接 PORTA_PA7

9CLK0输入0的脉冲
15CLK1输入1的脉冲
18CLK2输入2的脉冲
*/

#ifndef _8254_H
#define _8254_H

#define uchar unsigned char
#define uint unsigned int

#define counter_data_port_dire DDRB //所用的数据口的方向寄存器
#define counter_data_port PORTB     //所用的数据口
#define wr PORTA_PA0
#define rd PORTA_PA1
#define CS PORTA_PA2
#define A1 PORTA_PA3
#define A0 PORTA_PA4
#define GT0 PORTA_PA5
#define GT1 PORTA_PA6
#define GT2 PORTA_PA7

#define Count_Time_0 1   //计数的周期,Nms
#define Count_Time_1 1
#define Count_Time_2 1
#define N_Coder_0 500   //编码器线数
#define N_Coder_1 500
#define N_Coder_2 500

void counter_8254_init(void);

void counter_8254_read(void);

void speed_result(void);

#endif

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
L8254.C

#include <hidef.h>
#include "derivative.h"
#include "8254.h"

/****************************************
函数void counter_8254_read_N(void)
功能:读8254的N计数器当前计数值
说明:
*******************************************/
void counter_8254_read(void)
{
  uint num_L= 0,num_H = 0;
  extern long int num_8254_0;
  extern long int num_8254_1;
  extern long int num_8254_2;
//////////////////////////                  
  counter_data_port_dire = 0xFF;       
  counter_data_port = 0x00;
  A1 = 1;
  A0 = 1;
  rd = 1;
  wr = 0;
  CS = 0;              
  CS = 1;
  wr = 1;
  
  CS = 0;
  wr = 1;       
  rd = 0;
  A0 = 0;
  A1 = 0;
  counter_data_port_dire = 0x00;
  num_L = counter_data_port;             
  CS = 1;  
  wr = 1;
  
  CS = 0;
  wr = 1;       
  rd = 0;
  A0 = 0;
  A1 = 0;   
  num_H = counter_data_port;   
  
  num_L = 0xFF - num_L; //分两次读出,由于82C54是减法计数器,所以要被OxFF减
  num_H = 0xFF - num_H;
  num_8254_0 = (long int)num_H*256+num_L; //将两个八位整合成一个十六位数据
             
  CS = 1;
  wr = 1;
  
  CS = 0;
  wr = 1;       
  rd = 0;
  A0 = 1;
  A1 = 0;
  counter_data_port_dire = 0x00;
  num_L = counter_data_port;            
  CS = 1;  
  wr = 1;
  
  CS = 0;
  wr = 1;       
  rd = 0;
  A0 = 1;
  A1 = 0;   
  num_H = counter_data_port;   
  
  num_L = 0xFF - num_L; //分两次读出,由于82C54是减法计数器,所以要被OxFF减
  num_H = 0xFF - num_H;
  num_8254_1 = (long int)num_H*256+num_L; //将两个八位整合成一个十六位数据
             
  CS = 1;
  wr = 1;
  
  CS = 0;
  wr = 1;       
  rd = 0;
  A0 = 0;
  A1 = 1;  
  counter_data_port_dire = 0x00;
  num_L = counter_data_port;           
  CS = 1;  
  wr = 1;
  
  CS = 0;
  wr = 1;       
  rd = 0;
  A0 = 0;
  A1 = 1;   
  num_H = counter_data_port;  
  
  num_L = 0xFF - num_L; //分两次读出,由于82C54是减法计数器,所以要被OxFF减
  num_H = 0xFF - num_H;
  num_8254_2 = (long int)num_H*256+num_L; //将两个八位整合成一个十六位数据
}

/****************************************
函数void speed_result(void)
功能:通过计数器的值来计算相应的转速
说明:
*******************************************/  
void speed_result(void)
{
  extern long int speed_count_0;
  extern long int num_8254_0;
  extern long int speed_count_1;
  extern long int num_8254_1;
  extern long int speed_count_2;
  extern long int num_8254_2;
  
  counter_8254_read();

  speed_count_0 = num_8254_0*(1000/Count_Time_0)/N_Coder_0;
  speed_count_1 = num_8254_1*(1000/Count_Time_1)/N_Coder_1;
  speed_count_2 = num_8254_2*(1000/Count_Time_2)/N_Coder_2;
}

/****************************************
函数:void counter_8254_init(void)
功能:8254的计数器的初始化
说明:对8254进行控制字写入并设置计数初值
*******************************************/  

void counter_8254_init(void)
{
  //计数初始化
  CS = 0;
  GT0 = 1;   //#0           
  GT1 = 1;
  GT2 = 1;
  
  CS = 1;
  wr = 1;
  
  counter_data_port_dire = 0xFF;
  
  counter_data_port = 0x30;        //选择0#。先低8再高8位,方式0,二进制16位计数方式
  A1 = 1;
  A0 = 1;   //写控制字
  wr = 0;   //写操作
  CS = 0;
  rd = 1;
  
  CS = 1;
  wr = 1;

  counter_data_port = 0x70;        //选择1#。先低8再高8位,方式0,二进制16位计数方式
  A1 = 1;
  A0 = 1;   //写控制字
  wr = 0;   //写操作
  CS = 0;
  rd = 1;
  
  CS = 1;
  wr = 1;
  

  counter_data_port = 0xB0;        //选择2#。先低8再高8位,方式0,二进制16位计数方式
  A1 = 1;
  A0 = 1;   //写控制字
  wr = 0;   //写操作
  CS = 0;
  rd = 1;
  
  CS = 1;
  wr = 1;   

//////////////////////////
  counter_data_port = 0xFF;   //低        
  A0 = 0;
  A1 = 0;   //#0  
  rd = 1;       
  wr = 0;   //写
  CS = 0;
  
  wr = 1;        
  CS = 1;
  
  counter_data_port = 0xFF;   //高        
  A0 = 0;
  A1 = 0;   //#0
  rd = 1;       
  wr = 0;   //写
  CS = 0;
  
  wr = 1;
  CS = 1;
  
//////////////////////////
  counter_data_port = 0xFF;   //低        
  A0 = 1;
  A1 = 0;   //#1  
  rd = 1;       
  wr = 0;   //写
  CS = 0;
  
  wr = 1;        
  CS = 1;
  
  counter_data_port = 0xFF;   //高         
  A0 = 1;
  A1 = 0;   //#1
  rd = 1;       
  wr = 0;   //写
  CS = 0;
  
  wr = 1;
  CS = 1;  

//////////////////////////
  counter_data_port = 0xFF;   //低        
  A0 = 0;
  A1 = 1;   //#2  
  rd = 1;       
  wr = 0;   //写
  CS = 0;
  
  wr = 1;        
  CS = 1;  
  
  counter_data_port = 0xFF;   //高        
  A0 = 0;
  A1 = 1;   //#2
  rd = 1;       
  wr = 0;   //写
  CS = 0;
  
  wr = 1;
  CS = 1;
  
  counter_data_port = 0x00;
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
3条回答
wye11083
1楼-- · 2020-02-02 10:43
时序问题吧。Ax必须在CS拉低之前稳定下来。即 CS# => 地址|数据 => RD#/WR# => RD/WR => CS才可以正常工作。因为芯片输出的数据是RD下降沿锁存的。(#表示拉低,没有#表示拉高)

CS = 0;
  wr = 1;        
  rd = 0;
  A0 = 0;
  A1 = 0;   
  num_H = counter_data_port;   
  
  num_L = 0xFF - num_L; //分两次读出,由于82C54是减法计数器,所以要被OxFF减
  num_H = 0xFF - num_H;
  num_8254_0 = (long int)num_H*256+num_L; //将两个八位整合成一个十六位数据

你看你上面的A在CS#拉低之后才赋值。所以在这个读周期完成之后才会真正变为0地址。

估计你有得忙了,好多时序都要改。必须要保证CS#有效前WR和RD都是无效的,而且CS无效前WR和RD都变无效。异步读写时序的要求,所有的芯片手册一般都是这样的。
septstrings
2楼-- · 2020-02-02 12:51
wye11083 发表于 2012-4-4 06:13
时序问题吧。Ax必须在CS拉低之前稳定下来。即 CS# => 地址|数据 => RD#/WR# => RD/WR => CS才可以正常工作 ...

懂了……(⊙o⊙)嗯  还好,这个改起来简单,改一个复制三份就好~~谢谢你了!
justchenchen
3楼-- · 2020-02-02 16:41
 精彩回答 2  元偷偷看……

一周热门 更多>