⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 adc_sram.c

📁 基于AVR单片机 Atmel Mega128的AD采集程序。
💻 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 + -