📄 adc_sram.c
字号:
#include <avr/io.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <stdlib.h>
#include <inttypes.h>
#include "adc_sram.h"
#include "macro.h"
//全局变量/////////////////////////////
extern uint8_t global_sample_mode_flag;//采样方式标志:手动或自动
extern uint16_t global_ad_counter;//AD转换计数器
extern uint8_t global_operation_detected_flag;//检测到动作标志
uint8_t global_channel_flag;//通道标志
extern uint16_t global_close_counter;//合闸线圈地址计数器
extern uint16_t global_trip_counter;//分闸线圈地址计数器
extern uint16_t global_motor_counter;//打压电机地址计数器
extern uint16_t global_voltage_counter;//操作电压地址计数器
extern uint8_t global_ad_finish_flag;//AD转换结束标志
//AD板子的初始化,包括端口方向,串口初始化等
void INITIATION(void)
{
DDRC=0xFF;//端口C输出
PORTC=0xFF;
DDRF|=0x0F;//端口F输出
sbi(DDRB,2);//CONVST初始化,输出
sbi(PORTB,2);
sbi(DDRG,0);//WR初始化,输出1
sbi(PORTG,0);
sbi(DDRG,1);//RD初始化,输出1
sbi(PORTG,1);
sbi(DDRG,2);//ALE初始化,输出1
sbi(PORTG,2);
sbi(DDRD,5);//CS_ADC初始化,输出1
sbi(PORTD,5);
sbi(DDRD,6);//CS_RAM初始化,输出1
sbi(PORTD,6);
UART_SETTING(19200,7372800);//串口初始化
sbi(DDRE,2);//串口接收控制
cbi(PORTE,2);
}
//延时程序
void delay_ms(void)
{
uint8_t i;
for(i=0;i<0x01;i++){;}
}
//开外部中断
void EXTERN_INTERRUPT_OPEN(uint8_t index)
{
EICRA=0xAA;
EICRB=0xAA;//设置下降沿触发
sbi(EIMSK,index);
sbi(SREG,7);//将寄存器SREG的“I”置1
}
//关外部中断
void EXTERN_INTERRUPT_CLOSE(uint8_t index)
{
cbi(EIMSK,index);
// sbi(SREG,7);//将寄存器SREG的“I”置1
}
//SRAM写操作
void SRAM_1M_8_WRITE(uint32_t address,uint8_t data)
{
//变量定义
// uint8_t addr_l,addr_m,addr_h;
//
cbi(PORTD,6);//ram片选拉低
sbi(PORTD,5);//AD片选拉高
DDRA=0xFF;//a口输出
// addr_h=(address>>16);//高4位地址
// addr_h=(addr_h&0x0F);
// addr_m=(address>>8);//中间8位地址
// addr_l=address;//低8位地址
// PORTA=addr_l;//写ram地址
// PORTC=addr_m;
// PORTF&=0xF0;//低4位清零
// PORTF|=addr_h;
PORTA=address;//低8位地址
PORTC=(address>>8);//中间8位地址
PORTF&=0xF0;//低4位清零
PORTF|=(address>>16)&0x0F;
cbi(PORTG,2);//地址锁存
PORTA=data;//将数据放在总线上
cbi(PORTG,0);//写拉低
delay_ms();//延时//////////////////
sbi(PORTG,0);//写拉高
sbi(PORTG,2);//去锁存
}
//SRAM读操作
uint8_t SRAM_1M_8_READ(uint32_t address)
{
uint8_t addr_l,addr_m,addr_h,temp;
cbi(PORTD,6);//ram片选拉低
sbi(PORTD,5);//AD片选拉高
DDRA=0xFF;//a口输出
addr_l=address;//低8位地址
addr_m=(address>>8);//中间8位地址
addr_h=(address>>16);//高4位地址
addr_h=(addr_h&0x0F);
PORTA=addr_l;//输出ram地址
PORTC=addr_m;
PORTF&=0xF0;//低4位清零
PORTF|=addr_h;
cbi(PORTG,2);//地址锁存
cbi(PORTG,1);//读拉低
delay_ms();//延时//////////////////
DDRA=0x00;//a口输入
PORTA=0xFF;//设置上拉
temp=PINA;//读取总线上的数据
sbi(PORTG,1);//读拉高
sbi(PORTG,2);//去锁存
sbi(PORTD,6);//去掉片选信号
return temp;
}
//AD写操作
void AD7891_WRITE(uint16_t cmd)
{
//CS:PD5;WR:PG0;RD:PG1
//DATA0~DATA7:PORTA
//ADCD8~ADCD11:PB4~PB7
uint8_t addr_h;
DDRA=0xFF;//a口输出
DDRB|=0xF0;//端口B高4位输出
// addr_l=cmd;
addr_h=(cmd>>8);
addr_h=(addr_h<<4);//低4位移动到高位
addr_h&=0xF0;//取高4位
//片选
cbi(PORTD,5);//ad片选拉低
sbi(PORTD,6);//ram片选拉高
PORTA=cmd;
PORTB&=0x0F;//高4位清零
PORTB|=addr_h;
cbi(PORTG,0);//写拉低
delay_ms();
sbi(PORTG,0);//写拉高
}
//AD读操作,返回一16位整数
uint16_t AD7891_READ(void)
{
//CS:PD5;WR:PG0;RD:PG1
//DATA0~DATA7:PORTA
//ADCD8~ADCD11:PB4~PB7
uint8_t result_l,result_h;
uint16_t result;
////////设置端口方向////////////////
DDRA=0x00;//PORTA as input
PORTA=0xFF;//设置上拉
DDRB&=0x0F;//PB4~PB7 as input
PORTB|=0xF0;//PB4~PB7设置上拉
////////读///////////////////////////
//片选
cbi(PORTD,5);//ad片选拉低
sbi(PORTD,6);//ram片选拉高
cbi(PORTG,1);//读拉低
delay_ms();
result_l=PINA;
result_h=PINB;
result_h&=0xF0;
result=result_h;
result=result<<4;
result|=result_l;
sbi(PORTG,1);//读拉高
return result;
}
//AD通道选择,index:1~8
void AD7891_CHANNEL_SELECT(uint16_t index)
{
index--;//0~7
index=(index<<3);
index&=0x38;//00111000,保留A2、A1、A0,将其它位屏蔽
AD7891_WRITE(index);
}
//AD转换开始
void AD7891_CONVERSION_START(void)
{
cbi(PORTB,2);//拉低CONVST
delay_ms();
sbi(PORTB,2);//拉高CONVST,启动AD转换
}
//串口初始化设置,包括设置波特率、8位数据+1位STOP位、多机通讯模式设置
void UART_SETTING(int baud_rate, long fosc)
{
UBRR0L=(fosc/16/(baud_rate+1))%256;//设置波特率
UBRR0H=(fosc/16/(baud_rate+1))/256;
UCSR0A|=(1<<MPCM0);//多机通讯模式
// UCSR0B|=(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);//允许发送和接收,并允许接收中断
UCSR0C|=(1<<UCSZ01)|(1<<UCSZ00);//9位数据+1位STOP位,从机
UCSR0B|=(1<<UCSZ02);
}
//开串口接收中断
void UART_RXCINT_OPEN(void)
{
UCSR0B|=(1<<RXEN0)|(1<<TXEN0)|(1<<RXCIE0);//允许发送和接收,并允许接收中断
}
//关串口接收中断
void UART_RXCINT_CLOSE(void)
{
UCSR0B&=~(1<<RXCIE0);
}
//发送单字节
void UART_DATA_BYTE_SEND(uint8_t data)
{
uint8_t i;
sbi(PORTE,2);//改为发送状态
//延时等待
for(i=0;i<0xff;i++){;}
//等待UDRE被置位,否则对数据寄存器UDR的写操作将被忽略
if(!(UCSR0A&(1<<UDRE0)))
{
UCSR0A|=(1<<UDRE0);
}
//等待发送缓冲器空
while(!(UCSR0A&(1<<UDRE0))){;}
UDR0=data;//发送数据
loop_until_bit_is_set(UCSR0A,TXC0);//查询发送是否结束
UCSR0A=UCSR0A|(1<<TXC0);//因为没有使用发送结束中断,所以通过置数将TXC清零
cbi(PORTE,2);//改为接收状态
}
//发送一包数据,temp_data为包序号,从1开始编号
void SEND_ONE_PACKAGE(uint8_t temp_data)
{
//变量定义
uint8_t crc16,temp_array[512];
uint16_t i;
uint32_t address;
//校验码初始化
crc16=0;
crc16=crc16+2+temp_data;//加入地址和包序号校验
//根据包序号获得相应的数据,包序号从1开始编号
//合闸线圈电流数据地址
if((temp_data>=1)&&(temp_data<=8)){address=(temp_data-1)*512;}
//分闸线圈电流数据地址
if((temp_data>=9)&&(temp_data<=16)){address=(temp_data-8-1)*512+10000;}
//电机电流数据地址
if((temp_data>=17)&&(temp_data<=24)){address=(temp_data-16-1)*512+30000;}
//操作电压数据地址
if((temp_data>=25)&&(temp_data<=32)){address=(temp_data-24-1)*512+20000;}
//根据地址给要发送的一个数组的数据和校验码赋值
for(i=0;i<512;i++)
{
temp_array[i]=SRAM_1M_8_READ(address+i);//读取数据
crc16+=temp_array[i];//累加校验码
}
//发送数据包
UART_DATA_BYTE_SEND(2);//发送地址
UART_DATA_BYTE_SEND(temp_data);//发送包序号
for(i=0;i<512;i++)//发送512字节数据
{
UART_DATA_BYTE_SEND(temp_array[i]);
}
UART_DATA_BYTE_SEND(crc16);//发送校验码
}
//设定采样周期,定时器开始记数
void TIMER_BEGIN(void)
{
//预分频8
TCCR1B&=0xF8;//11111 000
TCCR1B|=0x02;//00000 010
//选择快速PWM模式
TCCR1B|=(1<<WGM12)|(1<<WGM13);
TCCR1A|=3<<WGM10;
//输出比较寄存器,按照晶振7.3728MM,采样频率8K
// OCR1A=115;//(1/7.3728M)*(预分频)*TOP=1/8K
// OCR1A=40;//(1/7.3728M)*(预分频)*TOP=1/16K
// OCR1A=230;//(1/7.3728M)*(预分频)*TOP=1/4K
// OCR1A=307;//(1/7.3728M)*(预分频)*TOP=1/3K
OCR1A=10;//测试用
}
//定时器结束计时
void TIMER_STOP(void)
{
//将预分频置0,终止定时器
TCCR1B&=0xF8;//1111 1000
}
//数据采集程序
void SAMPLE(void)
{
//变量定义
uint16_t test_counter=0;
uint16_t int16_temp;
uint16_t i;
//全局变量初始化
global_ad_counter=0;//采样计数器清零
global_channel_flag=0;//采样通道清零
global_close_counter=0;//合闸线圈地址计数器
global_trip_counter=10000;//分闸线圈地址计数器
// global_motor_counter=20000;//打压电机地址计数器
global_voltage_counter=20000;//操作电压地址计数器
//启动定时器,采样周期在这里设置
// TIMER_BEGIN();
//当采样个数不足时,进行此循环
while(global_ad_counter<6000)//6000
// while(global_ad_counter<12000)//6000
{
//AD转换结束标志初始化
global_ad_finish_flag=0;
//选择采样通道
if(global_channel_flag==3){global_channel_flag=1;}
else{global_channel_flag++;}
if(global_channel_flag==3)
{
AD7891_CHANNEL_SELECT(4);
}
else
{
AD7891_CHANNEL_SELECT(global_channel_flag);
}
//启动AD转换
AD7891_CONVERSION_START();
//等待AD转换结束标志被赋值
while(global_ad_finish_flag!=0xFF){;}
//延时
for(i=0;i<7;i++)
{
;
}
PORTG^=0x08;//测试用???????????
//等待定时器溢出,AD结束中断处理在等待过程中完成
// while(!(TIFR&(1<<OCF1A))){;}
// TIFR|=1<<OCF1A;
//选中AD(因为在AD中断里去掉了AD的片选)
cbi(PORTD,5);
}
//AD计数清零
global_ad_counter=0;
//终止定时器
// TIMER_STOP();
//AD片选去掉
cbi(PORTD,5);
}
//检测动作是否开始程序
uint8_t OPERATION_DETECTION(void)
{
//变量定义
uint16_t int16_temp;
//采样计数器清零
global_ad_counter=0;
//检测到动作标志清零
global_operation_detected_flag=0;
//启动定时器,采样周期在这里设置
// TIMER_BEGIN();
//当没有检测到动作时,进行此循环
while(global_operation_detected_flag==0)
{
//AD转换结束标志初始化
global_ad_finish_flag=0;
//选择采样通道
int16_temp=global_ad_counter%2;
//通道1为合闸线圈电流
if(int16_temp==0){AD7891_CHANNEL_SELECT(1);}
//通道2为分闸线圈电流
if(int16_temp==1){AD7891_CHANNEL_SELECT(2);}
//启动定时器,采样周期在这里设置
// TIMER_BEGIN();
//启动AD转换
AD7891_CONVERSION_START();
//等待AD转换结束标志被赋值
while(global_ad_finish_flag!=0xFF){;}
//等待定时器溢出,AD结束中断处理在等待过程中完成
// while(!(TIFR&(1<<OCF1A))){;}
// TIFR|=1<<OCF1A;
//选中AD(因为在AD中断里去掉了AD的片选)
cbi(PORTD,5);
}
//如果检测到了动作开始
//向主机发送自动测试开始命令0x33
// UART_DATA_BYTE_SEND(0x33);
//AD计数清零
global_ad_counter=0;
//终止定时器
// TIMER_STOP();
//AD片选去掉
cbi(PORTD,5);
//检测到动作标志清零
global_operation_detected_flag=0;
//自动测试标志复原
global_sample_mode_flag=0xFF;
}
/*TIMER test//////////////////
//数据采集程序
void SAMPLE(void)
{
uint16_t count=0;//采样个数
//开外部中断7(AD转换结束中断)
// EXTERN_INTERRUPT_OPEN(7);
sbi(DDRE,3);
sbi(PORTE,3);
//启动定时器,采样周期0.5ms
TIMER_BEGIN();
// while(count<SAMPLE_NUMBER)//当采样个数不足时,进行此循环
while(1)//
{
//采样记数加1
count++;//放在这里,不影响采样间隔
PORTE=~PORTE;
//启动AD转换
//???
//等待定时器溢出
while(!(TIFR&(1<<TOV1))){;}
}
//终止定时器
TIMER_STOP();
}
*/
/*
//数据采集00000,00001存放数据个数
//1通道:00010H~1FFFFH
//2通道:20000H~3FFFFH
//3通道:40000H~5FFFFH
//4通道:60000H~7FFFFH
//5通道:80000H~9FFFFH
//6通道:A0000H~BFFFFH
//7通道:C0000H~DFFFFH
//8通道
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -