基于AVRmega128的modbus程序
- 格式:doc
- 大小:47.00 KB
- 文档页数:20
#include <mega128.h>#include <delay.h>#define TWIE 0#define TWEN 2#define TWWC 3#define TWSTO 4#define TWSTA 5#define TWEA 6#define TWINT 7#define TWPS0 0#define TWPS1 1#define TWS3 3#define TWS4 4#define TWS5 5#define TWS6 6#define TWS7 7#define TWGCE 0/*********主机发送模式状态码***********/#define START 0X08#define RE_START 0X10#define MT_SLA_ACK 0X18#define MT_SLA_NOACK 0X20#define MT_DATA_ACK 0X28#define MT_DATA_NOACK 0X30#define MT_ACK_FAUIL 0X38/*********主机接收模式状态码***********/#define MR_SLA_ACK 0X40#define MR_SLA_NOACK 0X48#define MR_DATA_ACK 0X50#define MR_DATA_NOACK 0X58/*********24C01地址***********/#define RD_DEVICE_ADDR 0XA1#define WD_DEVICE_ADDR 0XA0/******主模式写和读**************/#define start() (TWCR =(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)) // 启动#define stop() (TWCR =(1<<TWINT)|(1<<TWSTO)|(1<<TWEN)) // 停止#define wait() {while (!(TWCR & (1<<TWINT)));} // 等待中断发生#define test_ack() (TWSR & 0xF8) // 检测状态码#define set_ack() (TWCR |= (1<<TWEA)) // 做出ACK应答#define set_noack() (TWCR &= ~(1<<TWEA)) // 做出NOACK应答#define twi() (TWCR = (1<<TWINT)|(1<<TWEN)) // 再启动#define write_8_bit(x) {TWDR = (x);TWCR = (1<<TWINT)|(1<<TWEN);} // 写数据/*********显示端口定义***********/#define DIS_UNM PORTC#define wei_en PORTG|=0x04#define wei_cle PORTG&=0XFB#define duan_en PORTA|=0X80#define duan_cle PORTA&=0X7Fvoid PORT_INIT(void){DDRA=0XFF;PORTA=0X00;DDRC=0XFF;PORTC=0X00;DDRG=0XFF;PORTG=0X00;DDRD=0X00;PORTD=0X00;}void TWI_INIT(void);unsigned char IIC_WRITE(unsigned char wdata,unsigned char addr);unsigned char IIC_READ(unsigned char addr);void LED_display(unsigned int temp_data);unsigned char SEG7[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//共阴极unsigned char qian,bai,shi,ge,qian_data,bai_data,shi_data,ge_data,display_flag; void main(void){unsigned char i=0;PORT_INIT();TWI_INIT();i=IIC_READ(6);//delay_ms(15);i++;IIC_WRITE(i,6);//delay_ms(10);while(1){LED_display(i);}}void TWI_INIT(void){TWBR = 0X30;TWCR = 0X04;TWSR = 0X00;}unsigned char IIC_WRITE(unsigned char wdata,unsigned char addr){start();wait();if(test_ack()!=START) //判断是否是启动信号return 1;write_8_bit(WD_DEVICE_ADDR);//delay_ms(5); //写器件地址----找器件wait();if(test_ack()!=MT_SLA_ACK) //器件是否应答了return 1;write_8_bit(addr); //delay_ms(5); // 写器件中存储地址wait();if(test_ack()!=MT_DATA_ACK) //是否应答return 1;write_8_bit(wdata);// delay_ms(5); //向器件存储地址中写数据wait();if(test_ack()!=MT_DATA_ACK) //return 1;stop();return 0;}unsigned char IIC_READ(unsigned char addr){unsigned char temp;start();wait();if(test_ack()!=START)//return 1;write_8_bit(WD_DEVICE_ADDR);//delay_ms(5);//写器件地址----找器件wait();if(test_ack()!=MT_SLA_ACK) //return 1;write_8_bit(addr); // delay_ms(5); // 写器件中存储地址wait();if(test_ack()!=MT_DATA_ACK) //return 1;start(); //wait();if(test_ack()!=RE_START) //return 1;write_8_bit(RD_DEVICE_ADDR); //delay_ms(5); //读器件地址--读命令wait();if(test_ack()!=MR_SLA_ACK)// 主机接收return 1;twi();//重新启动IICwait();if(test_ack()!= MR_DATA_NOACK)return 1;temp=TWDR; //读出数据赋给变量stop();delay_ms(2); //此延时非同寻常!!! return temp;}void LED_display(unsigned int temp_data){qian_data=temp_data/1000;temp_data=temp_data%1000;bai_data=temp_data/100 ;temp_data=temp_data%100; //取余运算shi_data=temp_data/10 ;temp_data=temp_data%10; //取余运算ge_data=temp_data;qian=SEG7[qian_data];bai =SEG7[bai_data];shi =SEG7[shi_data];ge =SEG7[ge_data];switch(display_flag){case 0x00:duan_en;DIS_UNM=0x00;duan_cle;wei_en;DIS_UNM=0xFE;wei_cle;delay_ms(2);duan_en;DIS_UNM=ge;duan_cle;display_flag++;delay_ms(2);break;case 0x01:duan_en;DIS_UNM=0x00;duan_cle;wei_en;DIS_UNM=0xFD;wei_cle;delay_ms(2);duan_en;DIS_UNM=shi;duan_cle;display_flag++;delay_ms(2);break;case 0x02:duan_en;DIS_UNM=0x00;duan_cle;wei_en;DIS_UNM=0xFB;wei_cle;delay_ms(2);duan_en;DIS_UNM=bai;duan_cle;display_flag++;delay_ms(2);break;case 0x03:duan_en;DIS_UNM=0x00;duan_cle;wei_en;DIS_UNM=0xF7;wei_cle;delay_ms(2);duan_en;DIS_UNM=qian;duan_cle;display_flag=0;delay_ms(2); break;default:// DIS_UNM=0X00;}}。
Avr单片机中使用modbus协议的方法有幸做了个项目,其中使用到了单片机和上位机通讯的程序,上位机用组态实现功能,探索了些方法,写出来和大家分享一下,这些知识本不是什么秘密,本人参考了许多资料,自己整合了一下。
每种程序都是算法多样,最终功能实现就行。
大家做单片机串口通讯时是不是总想有一种以不变应万变的思想,就是在底层单片机硬件和软件不变的情况下,去适应任何上位机软件系统,当然可以实现,这就需要用到标准的通讯协议了,以下我就和大家分享一下我做的modbus协议(单片机端),如果上位机用组态软件的情况下,你直接使用通讯协议就行它会自动和单片机通讯。
大家在设计单片机程序时首先要定义好数据结构,先构想一下需要哪些采集数据,上位机需要查询什么数据,数据的类型和全局与否,运算的精度等等。
然后把上位机需要采集的数据用一个数组管理起来,便于modbus协议的实现。
单片机里串口通讯程序尽量用查询发送,中断接收的方式,要定义发送缓冲区和接收缓冲区,以便提高系统效率。
以下程序用gcc实现,单片机用avr单片机。
ISR(USART0_RX_vect)//串口0接收中断服务程序{volatile unsigned char status,data;cli();//关中断status = UCSR0A;//ucsr0a赋值状态标志data = UDR0;//接收的数据放入data变量usart0_rx_complete=0;//接收完成标志赋值0,还没有完成if ((status & (FRAMING_ERROR0 | PARITY_ERROR0 | DATA_OVERRUN0))==0)//如果各标志位正确则,执行以下{usart0_rx_count++;//接收缓冲区指针加一switch (usart0_rx_count){case 1:if(data==add//第一个字节是地址,读入内部本机地址进行比较{usart0_rx_buf[0]=data;TIMSK0=0x01;//启动定时器0,进行超时控制}else{usart0_rx_count=0;}break;case 2:if (((data==0x03)||(data==0x01)||(data==0x05)||(data==0x10))==0)//如果第一位不等于读指令0x03,01,05,10功能码,则清接收缓冲区指针{usart0_rx_count=0;}else//等于这几个功能码则进行,则将他放入接收数组,并预计接收数组长度,不是10码时都是8个字节{usart0_rx_buf[1]=data;if (data!=0x10){rx0_buf_size=8;}}break;case 3:usart0_rx_buf[2]=data;break;case 4:usart0_rx_buf[3]=data;break;case 5:usart0_rx_buf[4]=data;break;case 6:usart0_rx_buf[5]=data;break;case 7:usart0_rx_buf[6]=data;//10码时接收的字节计数if (usart0_rx_buf[1]==0x10){rx0_buf_size=9+usart0_rx_buf[6];}break;case 8:usart0_rx_buf[7]=data;//1,用10功能码时有效的数据位,system_reg_data的数据,这里规定最多接收26个字节(不带crc)break;case 9:usart0_rx_buf[8]=data;//2break;case 10:usart0_rx_buf[9]=data;//3break;case 11:usart0_rx_buf[10]=data;//4break;case 12:usart0_rx_buf[11]=data;//5break;case 13:usart0_rx_buf[12]=data;//6break;case 14:usart0_rx_buf[13]=data;//7 break;case 15:usart0_rx_buf[14]=data;//8 break;case 16:usart0_rx_buf[15]=data;//9 break;case 17:usart0_rx_buf[16]=data;//10 break;case 18:usart0_rx_buf[17]=data;//11 break;case 19:usart0_rx_buf[18]=data;//12 break;case 20:usart0_rx_buf[19]=data;//13 break;case 21:usart0_rx_buf[20]=data;//14 break;case 22:usart0_rx_buf[21]=data;//15 break;case 23:usart0_rx_buf[22]=data;//16 break;case 24:usart0_rx_buf[23]=data;//17 break;case 25:usart0_rx_buf[24]=data;//18 break;case 26:usart0_rx_buf[25]=data;//19 break;case 27:usart0_rx_buf[26]=data;//20 break;case 28:usart0_rx_buf[27]=data;//21 break;case 29:usart0_rx_buf[28]=data;//22break;case 30:usart0_rx_buf[29]=data;//23break;case 31:usart0_rx_buf[30]=data;//24break;case 32:usart0_rx_buf[31]=data;//25break;case 33:usart0_rx_buf[32]=data;//26break;case 34:usart0_rx_buf[33]=data;//27break;case 35:usart0_rx_buf[34]=data;//28break;}if(usart0_rx_count>=rx0_buf_size)//串口0接收到了指定个数的数组则{usart0_rx_count=0;//接收缓冲区指针清零usart0_rx_complete=1;//串口0接收完标志time0_num=0;//串口0的中断次数清零。
mega128串口通讯测试程序/********************************************************说明: 需要串口调协助实验(波特率设为9600)在串口调试助手中输入要发送的内容,点发送后M128会返回相同的数据CPU型号: ATMEGA128时钟: 8MHZ日期:2014.7.22默认9600 8 1********************************************************/#include#includevoid USART0_Init( void );void USART0_Transmit( unsigned char data );unsigned char USART0_Receive( void );void main(void){unsigned char n=0,tmp=0;DDRB |=0X10; //PB4设为输出PORTB|=0X10; //关闭PB4外接的LEDDDRF |=0X0E; //LED及数码管锁存IO口设为输出PORTF|=0X0E;DDRA=0XFF; //LED IO口设为输出PORTA=0XFF;PORTF&=0xF7; //锁存数据关闭LEDPORTA=0X00;PORTF&=0XF8; //锁存数据关闭数码管USART0_Init(); //波特率9600 初始化串口while(1){if(UCSR0A&(1<<="">{tmp=USART0_Receive(); //接收数据USART0_Transmit(tmp); //发送数据}}}void USART0_Init( void ){unsigned int tmp;UBRR0L=51; /* 设置波特率*/UCSR0B = (1<<rxen0)|(1<<="" p="" 接收器与发送器使能*=""> UCSR0C = (1<<ucsz00)|(1<<="" 个数据位,="" 设置帧格式:=""> // 数据发送【发送5 到8 位数据位的帧】void USART0_Transmit( unsigned char data ){/* 等待发送缓冲器为空*/while ( !( UCSR0A & (1<<="" p="">/* 将数据放入缓冲器,发送数据*/UDR0 = data;}// 数据接收【以5 到8 个数据位的方式接收数据帧】unsigned char USART0_Receive( void ){/* 等待接收数据*/while ( !(UCSR0A & (1<<="" p="">/* 从缓冲器中获取并返回数据*/return UDR0;}</ucsz00)|(1<</rxen0)|(1<。
Mega128单片机调试与设置一、单片机型号为ATmega128A二、调试软件为iccavr7.22和AVRstudio4.0连调三、流程:1.在iccavr中建立工程文件。
2.在iccavr中新建一个项目,并保存。
注意保存文件名必须为.c才可以。
如下图。
3.在右上方file里面右键添加.c 文件。
4.然后编写程序。
注意一般程序包括如下库文件:#include <iom128v.h>#include <macros.h>#include <stdio.h>#include <string.h>5.在利用系统生成(build)钱,一定要进行系统相关的设置,此项非常重要,否则会出现各种问题。
特别是单片机的选取,一定要按照下图选取,选择ATmega1280是不对的。
具体设置在project -> options6.设置完毕后,建立工程。
7.无错误应该为下图8.然后打开AVRstudio,打开projectwizard -> open,然后打开后缀名为.cof 的文件,如下图所示:然后会自动生成后缀名为.aps的工程文件9.然后选择10.连接成功后直接进入到如下界面11.点击黑色的AVR进行基本的设置单片机为ATmega128,JTAG mode ,然后添加 .hex 文件。
熔丝位的设置如下,只有这几个有“√”,特别要注意将M103C 的“√”去掉。
内部1M 晶振用外部8M 晶振用注意此处要修改烧入单片机的程序名称,后缀名为 .hex ,在iccavr 建立的工程文件里添加点击program 即将程序烧写进入单片机中其他一般不要设置。
12.都设置完毕后就可以进行debug或者是烧写程序了。
Debug点击绿色按钮或者在debug里选择。
AVR单片机mega128例程大全//16超声波LED显示#include //PA0接控制引脚PA7接接收引脚#include #define chao 100longint time=0;void delay(long int z){inti,j;for(i=0;i<z;i++)< bdsfid="72" p=""></z;i++)<> for(j=0;j<100;j++);}void main(){int o=0;DDRD=0xff;DDRA=0x0f;TCNT1H=0x00;TCNT1L=0x00;while(1){PORTA=0x0f;delay(1);PORTA=0x00;while((PINA&0x80)==0x00); TCCR1B=0x03; while((PINA&0x80)==0x80); TCCR1B=0x00;time=TCNT1H*256+TCNT1L; TCNT1H=0x00; TCNT1L=0x00;if(time<chao)< bdsfid="92" p=""></chao)<> {if(time<chao)< bdsfid="95" p=""></chao)<>{o=500;while(o--)PORTD=0x04;}}if(time>chao){if(time>chao){o=500;while(o--)PORTD=0x08;}}}}//AD#include#include#define unint unsigned int#define unchar unsigned char#pragma data:codeconst table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d, 0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};unint mega128_ad(){unintaddata;DDRF&=~BIT(0);ADMUX=0;ADCSRA=0X80;ADCSRA|=BIT(ADSC);while(!(ADCSRA&(BIT(ADIF)))); addata=ADCL;addata=addata+ADCH*256; returnaddata;}void show(count){unchar temp1,temp2,temp3,temp4; temp1=count/1000;temp2=(count%1000)/100;temp3=(count%100)/10;temp4=count%10;HC_595_OUT(table[temp4]); DDRB|=(1<<4);PORTB|=(1<<4);delay(10);DDRB|=(1<<4);PORTB&=~(1<<4);HC_595_OUT(table[temp3]); DDRB|=(1<<5);PORTB|=(1<<5);delay(10);DDRB|=(1<<5);PORTB&=~(1<<5);HC_595_OUT(table[temp2]); DDRB|=(1<<6);delay(10);DDRB|=(1<<6);PORTB&=~(1<<6);HC_595_OUT(table[temp1]);DDRB|=(1<<7);PORTB|=(1<<7);delay(10);DDRB|=(1<<7);PORTB&=~(1<<7);}void HC_595_OUT(count){PORTB&=~(1<<0);SPDR =count ;while(!(SPSR & (1<<spif)));< bdsfid="173" p=""></spif)));<> delay(10);PORTB|=(1<<0);}void delay(z){unintx,y;for(x=0;x<z;x++)< bdsfid="181" p=""></z;x++)<>for(y=0;y<200;y++);}void main(){unintcount,chl;DDRC |= (1<<7);PORTC &= (1<<7);DDRB |= (1<<2)|(1<<1)|(1<<0);SPCR = (1<<spe)|(1<<mstr)|(1<<spr0)|(1<<spr1);< bdsfid="192" p=""></spe)|(1<<mstr)|(1<<spr0)|(1<<spr1);<> while(1){count=mega128_ad();//用参数代替老是出问题,这一点需要再次认知考虑/*for(i=0;i<4;i++){ad[3-i]=shuzhi%10;shuzhi=shuzhi/10;}*/show(count);}}//ADC#include#include#define unint unsigned int#define unchar unsigned char#pragma data:codeconst table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d, 0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};unint mega128_ad(){unintaddata;DDRF&=~BIT(0);PORTF&=~BIT(0);ADMUX=0;ADCSRA=0X80;ADCSRA|=BIT(ADSC);while(!(ADCSRA&(BIT(ADIF)))); addata=ADCL; addata=addata+ADCH*256; returnaddata; }void show(count){unchar temp1,temp2,temp3,temp4;temp1=count/1000;temp2=(count%1000)/100;temp3=(count%100)/10;temp4=count%10;HC_595_OUT(table[temp4]);DDRB|=(1<<4);PORTB|=(1<<4);delay(10);DDRB|=(1<<4);PORTB&=~(1<<4);HC_595_OUT(table[temp3]);DDRB|=(1<<5);PORTB|=(1<<5);delay(10);DDRB|=(1<<5);PORTB&=~(1<<5);HC_595_OUT(table[temp2]);DDRB|=(1<<6);PORTB|=(1<<6);delay(10);DDRB|=(1<<6);PORTB&=~(1<<6);HC_595_OUT(table[temp1]);DDRB|=(1<<7);PORTB|=(1<<7); delay(10);DDRB|=(1<<7);PORTB&=~(1<<7);}void HC_595_OUT(count) {PORTB&=~(1<<0);SPDR =count ;while(!(SPSR & (1<<spif)));< bdsfid="260" p=""></spif)));<> delay(10);PORTB|=(1<<0);}void delay(z){unintx,y;for(x=0;x<z;x++)< bdsfid="268" p=""></z;x++)<>for(y=0;y<200;y++);}void main()unintcount,chl;DDRC |= (1<<7);PORTC &= (1<<7);PORTB = 0x0F;DDRB |= (1<<2)|(1<<1)|(1<<0);SPCR = (1<<spe)|(1<<mstr)|(1<<spr0)|(1<<spr1);< bdsfid="278" p=""></spe)|(1<<mstr)|(1<<spr0)|(1<<spr1);<> while(1){count=mega128_ad();//用参数代替老是出问题,这一点需要再次认知考虑/*for(i=0;i<4;i++){ad[3-i]=shuzhi%10;shuzhi=shuzhi/10;}*/show(count);}}//CTC//该程序并未在示波器上测试,在仿真软件上仿真时只有PB5上有方波信号出现#include#include#define uchar unsigned char#define uint unsigned intvoid main(){DDRB|=0X60;TCCR1A=0X50;TCCR1B=0X09;OCR1A=0X7CF;}//D口矩阵键盘检测#include "config.h"#include#include#define unint unsigned int#define unchar unsigned charconst unsigned char Seg7_Data[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,0x00};unchar temp1,temp2,temp3,temp4; unintdata,z;void HC_595_init(){DDRC=0x80;PORTC=0x00;PORTB=0x0F;DDRB=0x07;SPCR =0x53;}void Seg7_Led_display(unint data) {unchar temp1,temp2,temp3,temp4;temp1=data/1000;temp2=(data%1000)/100;temp3=(data%100)/10;temp4=data%10;HC_595_OUT(Seg7_Data[temp4]);PORTB|=(1<<4);delay(20);PORTB&=~(1<<4);HC_595_OUT(Seg7_Data[temp3]);PORTB|=(1<<5);delay(20);PORTB&=~(1<<5);HC_595_OUT(Seg7_Data[temp2]); PORTB|=(1<<6); delay(20);PORTB&=~(1<<6);HC_595_OUT(Seg7_Data[temp1]);PORTB|=(1<<7);delay(20);PORTB&=~(1<<7);}void HC_595_OUT(unchar data){PORTB=0x06;SPDR =data ;while(SPSR==0);delay(10);PORTB=0x01;}void delay(unint z){uninti,j;for(i=0;i<z;i++)< bdsfid="360" p=""></z;i++)<> for(j=0;j<100;j++);}void delay_1us(void) //1us延时函{asm("nop");}void delay_nus(unsigned int n) //N us延时函数{ unsignedint i=0;for (i=0;i<n;i++)< bdsfid="370" p=""></n;i++)<> delay_1us();}void delay_1ms(void) //1ms延时函数{unsignedint i;for (i=0;i<1140;i++);}void delay_nms(unsigned int n) //N ms延时函数{unsignedint i=0;for (i=0;i<n;i++)< bdsfid="382" p=""></n;i++)<> delay_1ms();voidBuzz_init(void){DDRG |= (1<<4);PORTG &=~ (1<<4);}void Beep(unsigned intH_time,unsignedintL_time) { PORTG |= (1<<4);delay_nms(H_time);PORTG &=~ (1<<4);delay_nms(L_time);}intkey_press(void){int k;delay_nms(5);PORTD=0x01;delay_nms(5);if((PIND&0xF0)!=0x00){delay_nms(10);if((PIND&0xF0)!=0x00){if(PIND==0x11) {Beep(100,50); PORTA=0x1F;k=1;}else if(PIND==0x21) { Beep(100,50); PORTA=0xFD; k=2;}else if(PIND==0x41) { Beep(100,50); PORTA=0xFB; k=3;}else if(PIND==0x81) { Beep(100,50);。
科技与创新┃Science and Technology&Innovation ·90·2023年第21期文章编号:2095-6835(2023)21-0090-03基于MEGA128单片机的数控开关电源的设计卢启硕,秦琛(国网淮南市潘集区供电公司,安徽淮南232082)摘要:首先将交流电经过AD-DC整流单元电路转化为稳定直流电,滤波后经过DC-AC逆变电路转化为稳定的交流电,通过高频变压器后,接入整流单元滤波系统以获得所需要的直流电,通过反馈回路接入高频变压器的输出部分,再通过UC3844的高占空比获得一定的输出电流,并选用MEGA128单片微型机为主控制器件,设计的主要目的为控制高频变压器。
关键词:逆变电路;高频变压器;UC3844;数控开关电源中图分类号:TN86文献标志码:A DOI:10.15913/ki.kjycx.2023.21.026开关式电源技术与之前的技术相比有了很大提高,脉冲宽度调制(Pulse Width Modulation,PWM技术)得到广泛推广[1]。
使用20kHz的调制信号,可以使开关式电源的效率达到65%~75%,与之相比,线性电源的效率仅为30%~40%。
开关电源的工作原理比较简单,首先通过转换将220V的交流电源转化为高质量的直流电,再将得到的高品质的直流电转化为频率较高的交流电,最后整流得到直流电。
反馈电路采集输出电压,然后送到单片机将模拟量转变为数字量,处理之后调节输出的PWM脉冲占空比,经过以上处理变换以后才能得到与要求相符的直流电压,该直流电压的纹波和稳定性得到很大的改善[2]。
本文利用MEGA128单片机作为处理器,来设计输出电压可调的数字开关电源。
1硬件电路设计1.1主电路开关式电源的原理图如图1所示。
按照前文所述的步骤得到适合的直流电后,向单端反激式变换电路供电[3]。
选用功率MOSFET(金属氧化物半导体场效应晶体管)作为功率开关管,UC3844控制PWM脉冲的占空比,主要原理是UC3844控制MOSFET功率开关管的PWM的占空比,从而达到对输出电压的稳定控制。
自己学avr单片机已经有相当一段时间了,一开始用的是atmega128,觉得不是很好用。
于是自己去买了一块16L的芯片,觉得还行。
一开始用的是ICC A VR,应为它用起来比较简单,不像winavr那样,要写个Makefie,比较的麻烦,但icc avr的缺点是太过于简陋,调试程序时,感觉不是很好。
后来经同学介绍,用起了winavr,其实也是比较的简单,只不过要加一个makefile而已,其实makefile 可以用软件自带的组建自动生成,只需修改几个参数就可以用。
后来又用起了code vision avr,虽然不太习惯,也谈不上不好用.需要注意的是,三个不同的软件所带的同文件不一样。
icc avr 是iom128v.h(姑且以128为例),winavr是avr/io.h,不过makefile中要设置芯片为atmega128.而cvavr则是mega128.h。
记得一开始的时候,我对这些不同的同文件不是很理解,是从一个学长那里了解到,才弄明白的。
其实前两个软件只需把头文件稍微改一下基本上可以通用。
而最后一个软件的中断的写法似乎不太一样,因而和钱两个软件的兼容性是最差的。
总体说winavr给人的感觉是比较专业1、流水灯/*硬件环境:atmega128开发板软件环境:CodeVisionA VR-C*/#include <mega128.h>#define uchar unsigned char#define uint unsigned intuchar cnt;void timer1_init(){TCCR1B=0X00; //先停止定时器1TCNT1H=0XF0; //设定定时器初值TCNT1L=0XBE;TCCR1A=0X00; //启动定时器1TCCR1B=0X05; //使用1024分频}interrupt [TIM1_OVF] void timer1_ovf_isr(void){TCNT1H=0XF0; //重载定时器初值TCNT1L=0XBE;DDRE|=1<<2;PORTE|=1<<2;DDRA=0xff;PORTA=cnt; //输出led的值到端口Bcnt++;if(cnt==255)cnt=0;}void main(){//DDRB=0XFF;SREG|=0X80;TIMSK=0X04;timer1_init();while(1){;}}2、AD转换+数码管显示/***************************************************************************//*ADC测试程序*//*目标器件:ATmega128 *//*晶振:RC 8MHZ *//*编译环境:ICCA VR 7.13A *//*E-Mail:**********************//*时间:2010年11月13日*///Aref接A VCC(+5V),采用Aref作参考电压/*用数码管显示AD转换的结果*//***************************************************************************//*********************************包含头文件********************************/#include <iom128v.h>#include <macros.h>/********************************数码管段码表*******************************/ extern const unsigned char tab[]={0x3f,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};/*********************************全局变量**********************************/ unsigned int adc_rel=0;/****************************************************************************函数功能:ADC初始化函数入口参数:出口参数:****************************************************************************/ void adc_init(void){DDRF&=0XFE; //PORTF0设置为输入,即作为ADC0口输入模拟电压PORTF&=0XFE; //PORTF0设置为输入低电平ADCSRA=0x00; //关ADCADMUX = 0X00; //采用Aref作为参考电压,ADC0单端输入,右对齐ACSR=(1<<ACD);ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1);//ADEN,启动ADC;ADSC,ADC开始转换;ADIE,ADC中断使能;ADPSx,设置分频因子64}/**************************************************************************** 函数功能:ADC中断函数入口参数:出口参数:****************************************************************************/ #pragma interrupt_handler adc_isr:iv_ADCvoid adc_isr(void){//int data_h,data_l;//data_l=ADCL;//data_h=ADCH;ADCSRA = 0x00;ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADIE);adc_rel=ADC;/*if(adc_rel>0x1ff){PORTA|=1<<2;}elsePORTA&=~(1<<2);*/}/**************************************************************************** 函数功能:延时子程序入口参数:出口参数:****************************************************************************/ void delay(void){int i;for(i=0;i<1800;i++);}/**************************************************************************** 函数功能:显示子程序入口参数:k出口参数:****************************************************************************/ void display(unsigned int k)//发光二极管显示初始化{DDRE|=1<<2;PORTE|=1<<2;DDRA=0XFF;PORTA=k;}#define SS 0#define SCK 1#define MOSI 2#define MISO 3#define SS_H() PORTB|=(1<<SS)#define SS_L() PORTB&=~(1<<SS)#define led0_en() {DDRB|=1<<4;PORTB|=(1<<4);} //开第一个数码管的位选#define led0_dis() {DDRB|=1<<4;PORTB&=~(1<<4);} //关第一个数码管的位选#define led1_en() {DDRB|=1<<5;PORTB|=(1<<5);}#define led1_dis() {DDRB|=1<<5;PORTB&=~(1<<5);}#define led2_en() {DDRB|=1<<6;PORTB|=(1<<6);}#define led2_dis() {DDRB|=1<<6;PORTB&=~(1<<6);}#define led3_en() {DDRB|=1<<7;PORTB|=(1<<7);}#define led3_dis() {DDRB|=1<<7;PORTB&=~(1<<7);}#define OE 7#define point 3#define dp 7#include <iom128v.h>#include <macros.h>const unsigned char table[]={0x3F,0x06,0x5B,0x4F,0x66, //0,1,2,3,40x6D,0x7D,0x07,0x7F,0x6F, //5,6,7,8,90x77,0x7C,0x39,0x5E,0x79,0x71,0x00}; //a,b,c,d,e,fvolatile unsigned char led_buffer[4];void delay_1us(void) //1us延时函数{asm("nop");}void delay_nus(unsigned int n) //N us延时函数{unsigned int i=0;for (i=0;i<n;i++)delay_1us();}void delay_1ms(void) //1ms延时函数{unsigned int i;for (i=0;i<1140;i++);}void delay_nms(unsigned int n) //N ms延时函数{unsigned int i=0;for (i=0;i<n;i++)delay_1ms();}/*完成spi的初始化*/void spi_init(void){DDRB |= (1<<MOSI)|(1<<SCK)|(1<<SS);//设置MOSI,SCK输出SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<SPR1);//使能SPI,主机模式}/*spi主机传送数据*/void SPI_MasterTransmit(char Data){/* 启动数据传输*/SPDR = Data;/* 等待传输结束*/while(!(SPSR & (1<<SPIF)));}/*完成对HC595的初始化*/void HC_595_init(void){DDRC |= (1<<OE); //设置PORTC7为输出PORTC &= (1<<OE); //输出高电平,使能595PORTB = 0x0F; //同时打开四个数码管的位选spi_init();led_buffer[0]=16; //初始化数码管段码led_buffer[1]=16;led_buffer[2]=16;led_buffer[3]=16;}/*HC595完成传送数据*/void HC_595_OUT(unsigned char data){SS_L();SPI_MasterTransmit(data);SS_H();}void leddis_update(void){/*最低位数码管,第四个数码管*/if(point==0)HC_595_OUT(table[led_buffer[3]]|(1<<dp));elseHC_595_OUT(table[led_buffer[3]]);led0_en();delay_nus(60);led0_dis();if(point==1)HC_595_OUT(table[led_buffer[2]]|(1<<dp));elseHC_595_OUT(table[led_buffer[2]]);led1_en();delay_nus(60);led1_dis();if(point==2)HC_595_OUT(table[led_buffer[1]]|(1<<dp));elseHC_595_OUT(table[led_buffer[1]]);led2_en();delay_nus(60);led2_dis();/*最高位数码管,第一个数码管*/if(point==3)HC_595_OUT(table[led_buffer[0]]|(1<<dp));elseHC_595_OUT(table[led_buffer[0]]);led3_en();delay_nus(60);led3_dis();}void display_led(unsigned int data){if(data>9999){HC_595_OUT(0xFF);//当计数大于9999时,四个数码管同时输出8 PORTB|=((1<<4)|(1<<5)|(1<<6)|(1<<7));}else if(data>999){led_buffer[0]=data/1000;led_buffer[1]=(data%1000)/100;led_buffer[2]=(data%100)/10;led_buffer[3]=data%10;leddis_update();}else if(data>99){led_buffer[0]=data/1000; //关闭最高位的那个数码管led_buffer[1]=(data%1000)/100;led_buffer[2]=(data%100)/10;led_buffer[3]=data%10;leddis_update();}else if(data>9){led_buffer[0]=data/1000;led_buffer[1]=16;led_buffer[2]=(data%100)/10;led_buffer[3]=data%10;leddis_update();}else{led_buffer[0]=data/1000;led_buffer[1]=16;led_buffer[2]=16;led_buffer[3]=data%10;leddis_update();}}volatile unsigned int countnum=0;void timer1_init(void){TCCR1B = 0x00; //stopTCNT1H = 0x8F; //setupTCNT1L = 0x81;OCR1AH = 0x70;OCR1AL = 0x7F;OCR1BH = 0x70;OCR1BL = 0x7F;OCR1CH = 0x70;OCR1CL = 0x7F;ICR1H = 0x70;ICR1L = 0x7F;TCCR1A = 0x00;TCCR1B = 0x04; //start Timer}#pragma interrupt_handler timer1_ovf_isr:15void timer1_ovf_isr(void){TCNT1H = 0x8F; //reload counter high valueTCNT1L = 0x81; //reload counter low valuecountnum++;if(countnum>9999) countnum=0;}void init_devices(void){CLI(); //disable all interruptstimer1_init();TIMSK = 0x04; //timer interrupt sourcesSEI(); //re-enable interrupts}/**************************************************************************** 函数功能:主程序入口参数:出口参数:****************************************************************************/ void main(void){init_devices();HC_595_init();adc_init();SEI();//开全局中断变量display(0);while(1){delay();display_led(adc_rel/1024.0*5*1000);}}3、对EEPROM进行读写操作/************************************************文件:main.c用途:注意:内部8M晶振************************************************/#include "config.h"/*向EEPROM里面写入数据输入量:地址,数据*/void EEPROM_write(unsigned int uiAddress,unsigned char ucData) {while(EECR&(1<<EEWE)); //等待上一次写操作结束EEAR = uiAddress; //地址EEDR = ucData; //数据EECR |=(1<<EEMWE); //置位EEMWE,主机写使能EECR |=(1<<EEWE); //置位EEWE,写使能,启动写操作}/*从EEPROM指定的地址里面读出相应的数据*/unsigned char EEPROM_read(unsigned int uiAddress){while(EECR&(1<<EEWE)); //等待上一次写操作结束EEAR = uiAddress; //设置地址寄存器EECR |=(1<<EERE); //读使能return EEDR; //返回读入EEDR里面的数据}void main(void){unsigned char temp=123;unsigned char data;HC_595_init();EEPROM_write(0x01,temp);data=EEPROM_read(0x01);while(1){Seg7_Led_display(data); //调用显示函数将写入的数据又读出来 }}文件:eeprom12.rar大小:40KB下载:下载4、定时器0(轮循方式)/*定时器0和2(均为八位的定时计数器)有四种工作模式,此例是工作在普通模式。
基于MEGA128单片机的低能离子注入的无线智能控制系统的设计与实现刘南君;毛培宏【期刊名称】《新疆大学学报(自然科学版)》【年(卷),期】2013(000)001【摘要】Low energy ion implantation, as a new gene mutation method are widely used in biological breeding field. Aim at the problem in the electrical control mechanism of LZD1000 low energy ion implan-tation machine, a set of wireless intelligent control system was designed basedon AVRmega128 single chip microcomputer, and the system’s hardware and software debugging were completed. The results showed that the design and production of the master control board and LZD1000 low energy ion implantation machine system realized the good compatibility, and achieved the desired purpose.%低能离子注入作为一种新型基因诱变手段广泛应用于生物育种。
针对LZD1000型低能离子注入机在操作控制中存在的问题,本文设计了一套基于AVRmega128单片机的无线智能控制系统,完成了系统的硬件和软件的调试。
本设计制作的主控板与LZD1000型低能离子注入机系统实现了完好的兼容,达到了预期的目的。
TM1627_CN:/view/b3a01509763231126edb116a.html注:1、上述说明文档中图18的上拉电阻和电容是成对的接在STB、CLK、DIO上的。
2、我在测试电路中仅在DIO上使用了2kΩ的上拉电阻,没有使用电容。
且在使用10kΩ上拉电阻时没有读到正确的值,原因未知。
3、我使用的主控芯片为mega128(16MHz),使用引脚见程序。
4、说明文档中提到读取数据时需要在CLK上升沿读取DIO电平,但是我在使用中遇到CLK上升沿读取DIO电平不准确的情况,最后改为在CLK下降沿读取DIO电平,数据准确。
5、在下属程序使用前PA口的0、1、2位已初始化为输出状态。
6、对IO口初始化后调用disp()即可显示数字,调用key_get()可得到处理后的键值(处理方法因键盘设计而异)等待按键按下、松开与两个按键同时按下检测的程序段为:/*************************************************************************/unsigned char temp_kv=0,kv=0;/*************************************************************************/temp_kv = key_get();//将键值赋给temp_kvwhile((temp_kv==13)||(inover==1)) //等待按键按下temp_kv = key_get();kv = temp_kv; //获得键值while((temp_kv!=13)||(inover==1)) //等待按键松开或输入完成{temp_kv=key_get();if(temp_kv==12) //若两个功能键都被按下,kv=12;}/**************************************************************************///头文件tm1627.h#define TM1627_H//#include <avr/io.h>#define CLR_0_STB PORTA&=0xFE //STB:PA0#define SET_1_STB PORTA|=0x01#define CLR_0_CLK PORTA&=0xFD //CLK:PA1#define SET_1_CLK PORTA|=0x02#define CLR_0_DIO PORTA&=0xFB //DIO:PA2#define SET_1_DIO PORTA|=0x04#define DIO_READ DDRA&=0xFB /*DIO设为输入电平读取*/#define DIO_SEND DDRA|=0x04 /*DIO设为输出*///unsigned char table[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};extern unsigned char liangdu;extern unsigned char key_val;void delay_ms(unsigned char cn);void TM1627_write(unsigned char dat);unsigned char TM1627_read(void);void disp(unsigned int dat,unsigned char led);//显示函数显示一个unsigned int型数据并控制三个LED的亮暗unsigned char key_get(void);//返回已转换过的键值(0-12),其中键值12为S4和S12同时按下的键值//tm1627.c#include <avr/io.h>#include "tm1627.h"/*#define CLR_0_STB PORTA&=0xFE //STB:PA0#define SET_1_STB PORTA|=0x01#define CLR_0_CLK PORTA&=0xFD //CLK:PA1#define SET_1_CLK PORTA|=0x02#define CLR_0_DIO PORTA&=0xFB //DIO:PA2#define SET_1_DIO PORTA|=0x04*/unsigned char table[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//数码管码表unsigned char key[5];//unsigned char last_kv=12;void del(unsigned char cn){for(;cn>0;cn--);}unsigned char key_get(void){unsigned char i,j;unsigned char key_val;CLR_0_STB;TM1627_write(0x42);//读数据DIO_READ;// DDRA&=0xFB;//DIO设为输入// PORTA|=0x04;//使能上拉电阻TM1627j = PINA;for(i=0;i<5;i++){key[i]=TM1627_read();del(40);}SET_1_STB;DIO_SEND;// DDRA|=0x04;//DIO设为输出if(key[0]==0x01)key_val=1;else if(key[0]==0x08)key_val=2;else if(key[1]==0x18)key_val=12;else if(key[1]==0x01)key_val=3;else if(key[1]==0x08)key_val=10;else if(key[2]==0x01)key_val=4;else if(key[2]==0x08)key_val=5;else if(key[3]==0x01)key_val=6;else if(key[3]==0x08)key_val=0;else if(key[0]==0x02)key_val=7;else if(key[0]==0x10)key_val=8;else if(key[1]==0x02)key_val=9;else if(key[1]==0x10)key_val=11;elsekey_val=13;return key_val;}unsigned char TM1627_read(void) {unsigned char i;unsigned char temp=0;unsigned char bit;// SET_1_CLK;bit = PINA&0x04;for(i=0;i<8;i++){// temp>>=1;CLR_0_CLK;// for(j=0;j<20;j++);bit = PINA&0x04;if(bit == 0x04)temp|=0x80;//最高位置1SET_1_CLK;temp>>=1;// for(j=0;j<20;j++);}return temp;// SET_1_CLK;}void disp(unsigned int dat,unsigned char led) {// unsigned char ge,shi,bai,qian;unsigned char wei[4]={0,0,0,0};unsigned char i;wei[3]=dat%10;wei[2]=dat/10%10;wei[1]=dat/100%10;wei[0]=dat/1000;DDRA|=0x04;//DIO设为输出CLR_0_STB;TM1627_write(0x03);//7位10段SET_1_STB;delay_ms(5);CLR_0_STB;TM1627_write(0x40);//地址自动加一SET_1_STB;delay_ms(5);CLR_0_STB;TM1627_write(0xC0);//以下是14字节数据 for(i=0;i<4;i++){TM1627_write(table[wei[i]]);TM1627_write(0x00);}TM1627_write(led);TM1627_write(0x00);SET_1_STB;// delay_ms(5);CLR_0_STB;TM1627_write(liangdu);//脉冲宽度// TM1627_write(0x8F);//脉冲宽度SET_1_STB;}void TM1627_write(unsigned char dat){unsigned char i;// DIO_OUT(); //将DIO设置为推挽输出for(i=0;i<8;i++){CLR_0_CLK; //先将CLK置低if((dat&0x01)==0x01)SET_1_DIO; //将数据发至DAT线上elseCLR_0_DIO;dat >>= 1; //数据移位准备下一次的发送// delay_ms(3); //延时以等待TM1627接收SET_1_CLK; //将CLK置高del(10);}// SET_1_CLK;}void delay_ms(unsigned char cn)//不准确的延时{unsigned char i,j;for(;cn>0;cn--){for(i=0;i<100;i++)for(j=0;j<255;j++);}}电路原理图:。
AVR单片机Mega128 485通信程序一、实物测试二、程序//#include <io.h> //用这个头文件也可以#include <mega128.h>#include <string.h>#include <stdio.h>#define F_CPU 16000000 // 单片机主频为16MHz,用于延时子程序,熔丝位必须设置到外部高频晶振才行#include "Config.h" //配置头文件,与硬件相关的配置在这里更改#define LED0 PORTE.0#define LED1 PORTE.1#define LED2 PORTE.2#define LED3 PORTE.3#define LED4 PORTE.4#define LED5 PORTE.5#define LED6 PORTE.6#define LED7 PORTE.7#define PD4 PORTD.4unsigned char str[50]={0};unsigned char in=0,a=0,lage=0;//uchar usart_rx_data;void delay_ms(int ms){for(;ms>0;ms--);}//************************************************ ***********************// MSP430IO口初始化//************************************************ ***********************void Port_Init(){LEDDDR = 0xFF; //设置IO口方向为输出LED = 0xFF; //PE口初始设置为FFDDRD = 0x18; //设置为输入,并且要打开上拉电阻//DDRD = 0x00 | (1<<RS485_CTR_RDE)| (1<<PD3);//PORTD |= ((1 << PD1) |(1 << PD5)|(1 << PD6)|(1 << PD7)); //四位独立按键连接在PD1/PD5/PD6/PD7上}//************************************************ *************************// MSP430串口1初始化//************************************************ *************************void UART1_Init(){UCSR1A=0x00; //单倍速模式UCSR1B=0x98; //接收中断允许,发送结束和寄存器空中断关闭,采用查询发送模式//UCSR1B=0x08;//UCSR1C=(1<<UCSZ11)|(1<<UCSZ10); //写UCSRC寄存器,异步通信无校验,8位数据1位停止位UCSR1C=0x86;UBRR1H=0; //写波特率的值UBRR1L=103;}//************************************************ *************************// 串口1发送数据函数//************************************************ *************************void Send_Byte(uchar data){while(!(UCSR1A&(1<<UDRE1))); //等待发送寄存器空UDR1= str[data]; //写入发送数据while(!(UCSR1A&(1<<TXC1))); //等待发送完毕UCSR1A|=(1<<TXC1);delay_ms(5); //切换之前先有个小延时}//************************************************ *************************// 处理来自串口1的接收中断//************************************************ *************************//数据接收结束中断向量interrupt[USART1_RXC]void usart_rx_isr(void)//中断服务程序{str[in]=UDR1;LED0=0;if(str[in]!=0x0A) //$为停止标志{in++;}else{LED3=0;in=0;lage=1;}}//************************************************ *************************// 主函数//************************************************ *************************void main(void){DDRE=0xFF;PORTE=0XFF;Port_Init(); //端口初始化UART1_Init(); //串口设置初始化PD4=0; //切换到接收状态delay_ms(2);SREG|=0x80; //开启全局中断while(1) //无限循环{if(lage==1){PD4=1; //开启发送for(a=0;;a++){Send_Byte(a);if(str[a]==0x0A){//lage=0; //放在这个位置也可以//PD4=0; //放在这个位置也可以break; //跳出循环}}a=0;lage=0;LED5=0;PD4=0;}}三、仿真原理图。
雪松电子开发:/AVR mega128 技术文档1、电路分析图(1)mega128 核心板原理图 一,硬件电路说明 1,电源:1)通过 ISP 连接 USB 进行供电。
2)通过 JTAG 连接 USB 供电。
3)通过 P5 外接 5V 电源供电。
2,外围接口:P1,P2,P3,P4 共 64 位将 mega128 所有的接口全部引出,方便工程设 计和外围扩展。
3,发光二极管 D0 的作用是指示电源是否连接成功,如果外部电源成功的连接上,则发 光二极管发光指示电源连接成功;电阻 R0 的作用是对发光二极管进行限流,一般发光二极 管只能通过 5mA—15mA 左右的电流,且发光二极管上面的压降只需要 1.5V 左右,加到发 光二极管上面的电流如果超出额定值,则会烧毁。
而系统工作的电压是 5V,如果全部加在 发光二极管上, 则发光二极管很容易就会被烧毁。
所以要在电源和发光二极管之间串接一个 限流电阻。
该限流电阻阻值的计算: (VCC-发光二极管上的电压)/流过发光二极管的电流。
一般发光二极管的压降是 1.5V 左右,电流为 10mA 左右,为降低功耗我们在此取 680R 发光二极管 D1 和 R1 的作用是作为程序运行指示,在程序运行的过程中通过跳冒 P0 选 通 4,复位电路:单片机的第 20 脚(RESET,复位管脚)经过按钮 S0 连接到地。
分析:a)AVR 单片机是低电平复位(51 单片机是高电平复位,刚好相反) 。
需要 单片机复位时,最少要在复位管脚加上 1.5 微秒的低电平,才能确保单片机正确复位。
b)按下按钮 S0,复位管脚被直接拉到电源地,这样复位管脚的电平就被 拉低,从而使单片机复位;一般情况下按钮按下的时间超过毫秒级别,这样就能确保单片机“雪松电子开发”你身边的嵌入式开发专家雪松电子开发:/正确复位。
5, ISP 电路(程序下载电路) :ISP 下载接口不需要任何的外围零件。
可读性非常好的MODBUS源代码(1)为了加快发送采用了:数据空中断(2)为了保证最后一个字节能够发送到上位机采用了:发送完成中断#include <iom128v.h>#include <macros.h>#define _USART1_H#include "DMS2000.h"const UCHAR auchCRCHi[] = {0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40};const UCHAR auchCRCLo[] = {0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,0x43, 0x83, 0x41, 0x81, 0x80, 0x40};BOOL volatile USART1_send_mark = FALSE;UCHAR volatile USART1_sendPosi = 0;SHORT volatile USART1_receCount = 0;UCHAR volatile USART1_receTimeOut = 0;UCHAR volatile USART1_checkoutError = 0;UCHAR volatile USART1_sendCount = 0;UCHAR USART1_ch_type = 0;UCHAR USART1_set_number = 0;UCHAR USART1_send_buffer[MSCOMM_BUFFER_LENGTH]; UCHAR USART1_mscomm_buffer[MSCOMM_BUFFER_LENGTH];USHORT CRC16(UCHAR *puchMsg, USHORT usDataLen){UCHAR uchCRCHi = 0xFF;UCHAR uchCRCLo = 0xFF;ULONG uIndex;while (usDataLen--){uIndex = uchCRCHi ^ *puchMsg++;uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];uchCRCLo = auchCRCLo[uIndex];}return (uchCRCHi << 8 | uchCRCLo);}void USART1_Init(SHORT MSCOMM_baud){UCHAR me_STOP = (UCHAR)(MSCOMM_baud & 0x01); UCHAR me_UPM = (UCHAR)(MSCOMM_baud & 0x06) >> 0x01; UCHAR me_Baud = (UCHAR)(MSCOMM_baud & 0x38) >> 0x03;UCSR1B = 0x00;UCSR1A = 0x00;UCSR1C = (1 << UCSZ10) | (1 << UCSZ11);switch (me_STOP){case 0:UCSR1C |= (0 << USBS1);break;case 1:UCSR1C |= (1 << USBS1);break;}switch (me_UPM){case 0:case 1:UCSR1C |= ((0 << UPM11) | ( 0 << UPM10));break;case 2:UCSR1C |= ((1 << UPM11) | ( 0 << UPM10));break;case 3:UCSR1C |= ((1 << UPM11) | ( 1 << UPM10));break;}switch (me_Baud){case 0:UBRR1L = 0x3F;UBRR1H = 0x02;break;case 1:UBRR1L = 0x1F;UBRR1H = 0x01;break;case 2:UBRR1L = 0x8F;UBRR1H = 0x00;break;case 3:UBRR1L = 0x47;UBRR1H = 0x00;break;case 4:UBRR1L = 0x23;UBRR1H = 0x00;break;case 5:UBRR1L = 0x11;UBRR1H = 0x00;break;case 6:UBRR1L = 0x0B;UBRR1H = 0x00;break;default:UBRR1L = 0x05;UBRR1H = 0x00;break;}UCSR1B = (1 << RXEN1) | (1 << RXCIE1) | (1 << TXEN1);}BOOL USART1_CoilRegistersAddr(SHORT startAddr,SHORT registerAmount) {if (registerAmount >= 1 && registerAmount <= 2000){if (startAddr >= 0 && startAddr <= 4){if ((startAddr + registerAmount - 1) <= 4)return (TRUE);}}return (FALSE);}void USART1_GetCoilVal(SHORT *tempData,SHORT tempAddr){switch (tempAddr){case 0:*tempData = 0;break;}}void USART1_SetCoilVal(SHORT OnOff,SHORT tempAddr){}BOOL USART1_DiscreteRegistersAddr(SHORT startAddr,SHORT registerAmount) {if (registerAmount >= 1 && registerAmount <= 2000){if (startAddr >= 0 && startAddr <= 7){if ((startAddr + registerAmount - 1) <= 7)return (TRUE);}}return (FALSE);}void USART1_GetDiscreteVal(SHORT *tempData,SHORT tempAddr){switch (tempAddr){case 0:*tempData = 0;break;}}BOOL USART1_InputRegisterAddr(SHORT startAddr,SHORT registerAmount)if (registerAmount >= 1 && registerAmount <= 125){if (startAddr >= 0 && startAddr <= 7){if ((startAddr + registerAmount - 1) <= 7)return (TRUE);}}return (FALSE);}void USART1_GetInputRegisterVal(SHORT *tempData,SHORT tempAddr){switch (tempAddr){case 0:*tempData = 0;break;}}BOOL USART1_HoldingRegisterAddr(SHORT startAddr,SHORT registerAmount,UCHAR *set_number) {if (registerAmount >= 1 && registerAmount <= 125){if (startAddr >= 0 && startAddr < BUFFER_LENGTH){if ((startAddr + registerAmount - 1) < BUFFER_LENGTH){*set_number = startAddr + 1;return (TRUE);}}}return (FALSE);}void USART1_GetHoldingRegisterVal(SHORT *tempData,UCHAR set_number){}BOOL USART1_SetHoldingRegisterVal(SHORT tempData,SHORT tempAddr) {return (FALSE);}void USART1_Time_Proc(void){if (USART1_receTimeOut > 0){USART1_receTimeOut--;if (USART1_receTimeOut == 0 && USART1_receCount > 0){USART1_receCount = 0;USART1_checkoutError = 0;if (!USART1_send_mark)RS485_RECIVE();}}}void USART1_Begin_Send(void){RS485_SEND();NOP(); // --------|NOP(); // |NOP(); // |-----------等待总线释放NOP(); // |NOP(); // --------|NOP(); // --------|NOP(); // |NOP(); // |-----------等待总线释放NOP(); // |NOP(); // --------|USART1_send_mark = TRUE;USART1_sendPosi = 0;UCSR1B |= BIT(5);}void USART1_MODBUS_Error(UCHAR error_code){USHORT crcData;USART1_send_buffer[0] = USART1_mscomm_buffer[0];USART1_send_buffer[1] = USART1_mscomm_buffer[1] | 0x80;USART1_send_buffer[2] = error_code;crcData = CRC16(USART1_send_buffer,3);USART1_send_buffer[3] = crcData >> 8;USART1_send_buffer[4] = crcData & 0xff;USART1_sendCount = 5;USART1_Begin_Send();}void USART1_ReadCoilRegisters(void){UCHAR i,k;UCHAR byteCount;SHORT registerAmount;SHORT startAddr;SHORT tempAddr;SHORT tempData;USHORT crcData;startAddr = (SHORT)(USART1_mscomm_buffer[2] << 8) + (SHORT)USART1_mscomm_buffer[3]; registerAmount = (SHORT)(USART1_mscomm_buffer[4] << 8) + (SHORT)USART1_mscomm_buffer[5]; if (USART1_CoilRegistersAddr(startAddr,registerAmount)){tempAddr = startAddr;byteCount = registerAmount >> 0x03;if (registerAmount & 0x07)byteCount++;for (k = 0 ; k < byteCount ; k++){USART1_send_buffer[k + 3] = 0;for (i = 0 ; i < 8 ; i++){USART1_GetCoilVal(&tempData,tempAddr++);USART1_send_buffer[k + 3] |= (tempData << i);if (tempAddr >= startAddr + registerAmount)break;}USART1_send_buffer[0] = USART1_mscomm_buffer[0];USART1_send_buffer[1] = USART1_mscomm_buffer[1];USART1_send_buffer[2] = byteCount;byteCount += 3;crcData = CRC16(USART1_send_buffer,byteCount);USART1_send_buffer[byteCount] = crcData >> 8;byteCount++;USART1_send_buffer[byteCount] = crcData & 0xff;USART1_sendCount = byteCount + 1;USART1_Begin_Send();}elseUSART1_MODBUS_Error(2);}void USART1_ReadDiscreteRegisters(void){UCHAR i,k;UCHAR byteCount;SHORT registerAmount;SHORT startAddr;SHORT tempAddr;SHORT tempData;USHORT crcData;startAddr = (SHORT)(USART1_mscomm_buffer[2] << 8) + (SHORT)USART1_mscomm_buffer[3]; registerAmount = (SHORT)(USART1_mscomm_buffer[4] << 8) + (SHORT)USART1_mscomm_buffer[5]; if (USART1_DiscreteRegistersAddr(startAddr,registerAmount)){tempAddr = startAddr;byteCount = registerAmount >> 0x03;if (registerAmount & 0x07)byteCount++;for (k = 0 ; k < byteCount ; k++){USART1_send_buffer[k + 3] = 0;for (i = 0 ; i < 8 ; i++){USART1_GetDiscreteVal(&tempData,tempAddr++);USART1_send_buffer[k + 3] |= (tempData << i);if (tempAddr >= startAddr + registerAmount)break;}}USART1_send_buffer[0] = USART1_mscomm_buffer[0];USART1_send_buffer[1] = USART1_mscomm_buffer[1];USART1_send_buffer[2] = byteCount;byteCount += 3;crcData = CRC16(USART1_send_buffer,byteCount);USART1_send_buffer[byteCount] = crcData >> 8;byteCount++;USART1_send_buffer[byteCount] = crcData & 0xff;USART1_sendCount = byteCount + 1;USART1_Begin_Send();}elseUSART1_MODBUS_Error(2);}void USART1_ReadHoldingRegisters(void){UCHAR i;SHORT startAddr;SHORT registerAmount;SHORT byteCount;SHORT tempData;USHORT crcData;startAddr = (SHORT)(USART1_mscomm_buffer[2]<<8) + (SHORT)USART1_mscomm_buffer[3]; registerAmount = (SHORT)(USART1_mscomm_buffer[4]<<8) + (SHORT)USART1_mscomm_buffer[5]; if (USART1_HoldingRegisterAddr(startAddr,registerAmount,&USART1_set_number)){byteCount = registerAmount << 0x01;for (i = 0 ; i < registerAmount ; i++){USART1_GetHoldingRegisterVal(&tempData,USART1_set_number++);USART1_send_buffer[2*i+3] = tempData >> 8;USART1_send_buffer[2*i+4] = tempData & 0xff;}USART1_send_buffer[0] = USART1_mscomm_buffer[0];USART1_send_buffer[1] = USART1_mscomm_buffer[1];USART1_send_buffer[2] = byteCount;byteCount += 3;crcData = CRC16(USART1_send_buffer,byteCount);USART1_send_buffer[byteCount] = crcData >> 8;byteCount++;USART1_send_buffer[byteCount] = crcData & 0xff;USART1_sendCount = byteCount + 1;USART1_Begin_Send();}elseUSART1_MODBUS_Error(2);}void USART1_ReadInputRegisters(void){UCHAR i;SHORT startAddr;SHORT tempAddr;SHORT registerAmount;SHORT byteCount;SHORT tempData;USHORT crcData;startAddr = (SHORT)(USART1_mscomm_buffer[2]<<8) + (SHORT)USART1_mscomm_buffer[3]; registerAmount = (SHORT)(USART1_mscomm_buffer[4]<<8) + (SHORT)USART1_mscomm_buffer[5]; if (USART1_InputRegisterAddr(startAddr,registerAmount)){tempAddr = startAddr;byteCount = registerAmount << 0x01;for (i = 0 ; i < registerAmount ; i++){USART1_GetInputRegisterVal(&tempData,tempAddr++);USART1_send_buffer[2*i+3] = tempData >> 8;USART1_send_buffer[2*i+4] = tempData & 0xff;}USART1_send_buffer[0] = USART1_mscomm_buffer[0];USART1_send_buffer[1] = USART1_mscomm_buffer[1];USART1_send_buffer[2] = byteCount;byteCount += 3;crcData = CRC16(USART1_send_buffer,byteCount);USART1_send_buffer[byteCount] = crcData >> 8;byteCount++;USART1_send_buffer[byteCount] = crcData & 0xff;USART1_sendCount = byteCount + 1;USART1_Begin_Send();}elseUSART1_MODBUS_Error(2);}void USART1_ForceSingleCoil(void){UCHAR i;SHORT OnOff;SHORT startAddr;startAddr = (SHORT)(USART1_mscomm_buffer[2] << 8) + (SHORT)USART1_mscomm_buffer[3]; if (USART1_CoilRegistersAddr(startAddr,1)){OnOff = (SHORT)(USART1_mscomm_buffer[4] << 8) + (SHORT)USART1_mscomm_buffer[5]; switch (OnOff){case 0x00:USART1_SetCoilVal(0,startAddr);break;case 0xFF:USART1_SetCoilVal(1,startAddr);break;}if (USART1_mscomm_buffer[0] == module_addr){for (i = 0 ; i < 8 ; i++)USART1_send_buffer[i] = USART1_mscomm_buffer[i];USART1_sendCount = 8;USART1_Begin_Send();}}else if (USART1_mscomm_buffer[0] == module_addr)USART1_MODBUS_Error(2);}void USART1_PresetSingleHoldingRegister(void){UCHAR i;SHORT startAddr;SHORT tempData;startAddr = (SHORT)(USART1_mscomm_buffer[2]<<8) + (SHORT)USART1_mscomm_buffer[3];tempData = (SHORT)(USART1_mscomm_buffer[4]<<8) + (SHORT)USART1_mscomm_buffer[5];if (USART1_HoldingRegisterAddr(startAddr,1,&USART1_set_number)){if (USART1_mscomm_buffer[0] == module_addr){for (i = 0 ; i < 8 ; i++)USART1_send_buffer[i] = USART1_mscomm_buffer[i];USART1_sendCount = 8;USART1_Begin_Send();}if (USART1_SetHoldingRegisterVal(tempData,startAddr)){QUEUE_In_CRC16();EEPROM_START();}}else if (USART1_mscomm_buffer[0] == module_addr)USART1_MODBUS_Error(2);}void USART1_ForceMultipleCoil(void){UCHAR i,k;UCHAR byteCount;SHORT registerAmount;SHORT startAddr;SHORT tempAddr;SHORT OnOff;USHORT crcData;startAddr = (SHORT)(USART1_mscomm_buffer[2]<<8) + (SHORT)USART1_mscomm_buffer[3]; registerAmount = (SHORT)(USART1_mscomm_buffer[4] << 8) + (SHORT)USART1_mscomm_buffer[5]; if (USART1_CoilRegistersAddr(startAddr,registerAmount)){tempAddr = startAddr;byteCount = (SHORT)USART1_mscomm_buffer[6];if (USART1_mscomm_buffer[0] == module_addr){for (i = 0 ; i < 6 ; i++)USART1_send_buffer[i] = USART1_mscomm_buffer[i];crcData = CRC16(USART1_send_buffer,6);USART1_send_buffer[6] = crcData >> 8;USART1_send_buffer[7] = crcData & 0xff;USART1_sendCount = 8;USART1_Begin_Send();}for (k = 0 ; k < byteCount ; k++){for (i = 0 ; i < 8 ; i++){OnOff = USART1_mscomm_buffer[k+7] >> i;if (OnOff & 0x01)USART1_SetCoilVal(1,tempAddr++);elseUSART1_SetCoilVal(0,tempAddr++);if (tempAddr >= startAddr + registerAmount)break;}}}else if (USART1_mscomm_buffer[0] == module_addr)USART1_MODBUS_Error(2);}void USART1_PresetMultipleHoldingRegisters(void){UCHAR i;SHORT registerAmount;SHORT startAddr;SHORT tempData;USHORT crcData;BOOL Enable = FALSE;startAddr = (SHORT)(USART1_mscomm_buffer[2]<<8) + (SHORT)USART1_mscomm_buffer[3]; registerAmount = (SHORT)(USART1_mscomm_buffer[4]<<8) + (SHORT)USART1_mscomm_buffer[5]; if (USART1_HoldingRegisterAddr(startAddr,registerAmount,&USART1_set_number)){if (USART1_mscomm_buffer[0] == module_addr){for (i = 0 ; i < 6 ; i++)USART1_send_buffer[i] = USART1_mscomm_buffer[i];crcData = CRC16(USART1_send_buffer,6);USART1_send_buffer[6] = crcData >> 8;USART1_send_buffer[7] = crcData & 0xff;USART1_sendCount = 8;USART1_Begin_Send();for (i = 0 ; i < registerAmount ; i++){tempData = (SHORT)(USART1_mscomm_buffer[i*2+7]<<8) + (SHORT)USART1_mscomm_buffer[i*2+8]; if (USART1_SetHoldingRegisterVal(tempData,startAddr++))Enable = TRUE;}if (Enable){QUEUE_In_CRC16();EEPROM_START();}}elseUSART1_MODBUS_Error(2);}void USART1_Modbus_Analyze(void){SHORT tempData;USHORT crcData;if (USART1_receCount > 5){switch (USART1_mscomm_buffer[1]){case 1:if (USART1_receCount >= 8){UCSR1B &= ~BIT(7);if (USART1_mscomm_buffer[0] == module_addr && USART1_checkoutError == 0){crcData = CRC16(USART1_mscomm_buffer,6);if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7]) USART1_ReadCoilRegisters();}USART1_receCount = 0;USART1_checkoutError = 0;UCSR1B |= BIT(7);}break;case 2:if (USART1_receCount >= 8)UCSR1B &= ~BIT(7);if (USART1_mscomm_buffer[0] == module_addr && USART1_checkoutError == 0){crcData = CRC16(USART1_mscomm_buffer,6);if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7]) USART1_ReadDiscreteRegisters();}USART1_receCount = 0;USART1_checkoutError = 0;UCSR1B |= BIT(7);}break;case 3:if (USART1_receCount >= 8){UCSR1B &= ~BIT(7);if (USART1_mscomm_buffer[0] == module_addr && USART1_checkoutError == 0){crcData = CRC16(USART1_mscomm_buffer,6);if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7]) USART1_ReadHoldingRegisters();}USART1_receCount = 0;USART1_checkoutError = 0;UCSR1B |= BIT(7);}break;case 4:if (USART1_receCount >= 8){UCSR1B &= ~BIT(7);if (USART1_mscomm_buffer[0] == module_addr && USART1_checkoutError == 0){crcData = CRC16(USART1_mscomm_buffer,6);if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7]) USART1_ReadInputRegisters();}USART1_receCount = 0;USART1_checkoutError = 0;UCSR1B |= BIT(7);}break;case 5:if (USART1_receCount >= 8){UCSR1B &= ~BIT(7);if ((USART1_mscomm_buffer[0] == module_addr || USART1_mscomm_buffer[0] == 0) && USART1_checkout Error == 0){crcData = CRC16(USART1_mscomm_buffer,6);if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7]) USART1_ForceSingleCoil();}USART1_receCount = 0;USART1_checkoutError = 0;UCSR1B |= BIT(7);}break;case 6:if (USART1_receCount >= 8){UCSR1B &= ~BIT(7);if ((USART1_mscomm_buffer[0] == module_addr || USART1_mscomm_buffer[0] == 0) && USART1_checkout Error == 0){crcData = CRC16(USART1_mscomm_buffer,6);if (crcData == (USHORT)(USART1_mscomm_buffer[6] << 8) + (USHORT)USART1_mscomm_buffer[7]) USART1_PresetSingleHoldingRegister();}USART1_receCount = 0;USART1_checkoutError = 0;UCSR1B |= BIT(7);}break;case 15:if ((USART1_mscomm_buffer[0] == module_addr || USART1_mscomm_buffer[0] == 0) && USART1_checkout Error == 0){tempData = (SHORT)(USART1_mscomm_buffer[6]);tempData += 9;if (USART1_receCount >= tempData && USART1_receCount < MSCOMM_BUFFER_LENGTH){UCSR1B &= ~BIT(7);crcData = CRC16(USART1_mscomm_buffer,tempData - 2);if (crcData == (USHORT)(USART1_mscomm_buffer[tempData - 2] << 8) + (USHORT)USART1_mscomm_buff er[tempData - 1])USART1_ForceMultipleCoil();USART1_receCount = 0;USART1_checkoutError = 0;UCSR1B |= BIT(7);}}break;case 16:if ((USART1_mscomm_buffer[0] == module_addr || USART1_mscomm_buffer[0] == 0) && USART1_checkout Error == 0){tempData = (SHORT)(USART1_mscomm_buffer[4]<<8) + (SHORT)USART1_mscomm_buffer[5];tempData <<= 0x01;tempData += 9;if (USART1_receCount >= tempData && USART1_receCount < MSCOMM_BUFFER_LENGTH){UCSR1B &= ~BIT(7);crcData = CRC16(USART1_mscomm_buffer,tempData - 2);if (crcData == (USHORT)(USART1_mscomm_buffer[tempData - 2] << 8) + (USHORT)USART1_mscomm_buff er[tempData - 1])USART1_PresetMultipleHoldingRegisters();USART1_receCount = 0;USART1_checkoutError = 0;UCSR1B |= BIT(7);}}break;}}}/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 可靠地判断帧结束,防止通信停滞/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 利用单独的软件定时器,来判断一帧接收报文结束,可以防止若报文接收不完整,该帧通信任务无法结束而影响下一帧的接收。