前言
毕设用了IM1266模块联网传数据,但是苦于没有资料,做毕设的过程很煎熬的,参考了网上的类似的IM1281B的驱动,修修补补下终于算是做出来了,现在写下此博客,供以后的自己和开发者参考。
代码
初始化函数:
void usart3_init(u32 bound)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
//开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE); //串口3时钟使能
//复位串口3
USART_DeInit(USART3);
//GPIO设置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB11
//USART设置
USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为4800;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART3, &USART_InitStructure); //初始化串口 3
//设置NVIC中断优先级
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//清理缓存
IM266_clearBuf();
//使能接收中断
USART_ITConfig(USART3, USART_IT_RXNE|USART_IT_IDLE, ENABLE);//开启中断
USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);//开启中断
USART_Cmd(USART3, ENAB
中断函数:
vu16 USART3_RX_STA=0;
void USART3_IRQHandler(void)
{
char Res; //一个一个字节接收数据
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
Res =USART_ReceiveData(USART3);
if(USART3_RX_STA<USART3_MAX_RECV_LEN) //接收的字符串
{
Rx_Buffer_Pre[USART3_RX_STA]=Res;
USART3_RX_STA++;
}
}
//空闲中断,在收完数据后自动发送
if(USART_GetITStatus(USART3, USART_IT_IDLE) != SET)
{
receive_finished=1;
USART_ClearITPendingBit(USART3, USART_IT_IDLE);
}
USART3->SR;
USART3->DR;
// DEBUG_LOG("接收到IM1266数据");
}
读写函数:
//3:(地址:01H 命令:03H 数据长度:20H)+32:(数据段4x8=32)+2(CRC校验)=37:实际长度
unsigned char Tx_Buffer_Pre[8];
unsigned char Rx_Buffer_Pre[37];
//存放默认单位的数据:0.1V 0.001A等
unsigned char Read_ID=0x01;
unsigned long Voltage_data;
unsigned long Current_data;
unsigned long Power_data;
unsigned long Energy_data;
unsigned long Pf_data;
unsigned long CO2_data;
unsigned long Temp_data;
unsigned long HZ;
//存放常见单位的数据:1V 1A等
float Voltage_data_F;
float Current_data_F;
float Power_data_F;
float Energy_data_F;
float Pf_data_F;
float CO2_data_F;
float Temp_data_F;
float HZ_F;
int i=8;//此次发送数据的长度
int j=0;
int receive_finished;//完成标志位
int read_enable=0; //可读标志位
int reveive_numbe=37;//接收数据总长度
//自带
unsigned int calccrc(unsigned char crcbuf,unsigned int crc)
{
unsigned char i;
unsigned char chk;
crc=crc^crcbuf;
for(i=0;i<8;i++)
{
chk=( unsigned char)(crc&1);
crc=crc>>1;
crc=crc&0x7fff;
if (chk==1) crc=crc^0xa001;
crc=crc&0xffff;
}
return crc;
}
//自带
unsigned int chkcrc(unsigned char *buf,unsigned char len)
{
unsigned char hi,lo;
unsigned int i;
unsigned int crc;
crc=0xFFFF;
for(i=0;i<len;i++)
{
crc=calccrc(*buf,crc);
buf++;
}
hi=( unsigned char)(crc%256);
lo=( unsigned char)(crc/256);
crc=(((unsigned int)(hi))<<8)|lo;
return crc;
}
//修改 只需更改Tx_Buffer_Pre即可实现其他指令
void read_data(void)
{
union crcdata
{
unsigned int word16;
unsigned char byte[2];
}crcnow;
if(read_enable==1) // 到时间读数据
{
read_enable=0;
Tx_Buffer_Pre[0]=Read_ID; //模块的 ID 号,默认 ID 为 0x01
Tx_Buffer_Pre[1]=0x03;
Tx_Buffer_Pre[2]=0x00;
Tx_Buffer_Pre[3]=0x48;
Tx_Buffer_Pre[4]=0x00;
Tx_Buffer_Pre[5]=0x08;
crcnow.word16=chkcrc(Tx_Buffer_Pre,6);
Tx_Buffer_Pre[6]=crcnow.byte[1]; //CRC 效验低字节在前
Tx_Buffer_Pre[7]=crcnow.byte[0];
}
for(j=0;j<i;j++) //循环发送数据01 03 00 48 00 08 C4 1A
{
while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //串口三 循环发送,直到发送完毕
USART_SendData(USART3,Tx_Buffer_Pre[j]);
}
// DEBUG_LOG("发送IM1266读数据命令");
}
//修改
void Analysis_data(void)
{
union crcdata
{
unsigned int word16;
unsigned char byte[2];
}crcnow;
if(receive_finished==1) //接收完成
{
// reveive_numbe=USART3_RX_STA;
receive_finished=0;
if((Rx_Buffer_Pre[0]==0x01)||(Rx_Buffer_Pre[0]==0x00)) //确认 ID 正确
{
printf("\r\n确认 ID 正确\r\n");//串口一来打印接受电压值
crcnow.word16=chkcrc(Rx_Buffer_Pre,reveive_numbe-2);
if((crcnow.byte[0]==Rx_Buffer_Pre[reveive_numbe-1])&&(crcnow.byte[1]==Rx_Buffer_Pre[reveive_numbe-2]))//确认 CRC 校验正确
{
// printf("\r\n%d\r\n", USART3_RX_STA);
DEBUG_LOG("==================================================================================");
Voltage_data=(((unsigned long)(Rx_Buffer_Pre[3]))<<24)|(((unsigned long)(Rx_Buffer_Pre[4]))<<16)|(((unsigned long)(Rx_Buffer_Pre[5]))<<8)|Rx_Buffer_Pre[6];
Voltage_data_F=(float)(Voltage_data*0.0001);
printf("电压:%.4lf V\r\n",Voltage_data_F);//串口一来打印电压
Current_data=(((unsigned long)(Rx_Buffer_Pre[7]))<<24)|(((unsigned long)(Rx_Buffer_Pre[8]))<<16)|(((unsigned long)(Rx_Buffer_Pre[9]))<<8)|Rx_Buffer_Pre[10];
Current_data_F=(float)(Current_data*0.0001);
printf("电流:%.4lf A\r\n",Current_data_F);//串口一来打印电流
Power_data= (((unsigned long)(Rx_Buffer_Pre[11]))<<24)|(((unsigned long)(Rx_Buffer_Pre[12]))<<16)|(((unsigned long)(Rx_Buffer_Pre[13]))<<8)|Rx_Buffer_Pre[14];
Power_data_F=(float)(Power_data*0.0001);
printf("功率:%.4lf W\r\n",Power_data_F);//串口一来打印功率
Energy_data=(((unsigned long)(Rx_Buffer_Pre[15]))<<24)|(((unsigned long)(Rx_Buffer_Pre[16]))<<16)|(((unsigned long)(Rx_Buffer_Pre[17]))<<8)|Rx_Buffer_Pre[18];
Energy_data_F=(float)(Energy_data*0.0001);
printf("电能:%.4lf KWh\r\n",Energy_data_F);//串口一来打印电能
Pf_data= (((unsigned long)(Rx_Buffer_Pre[19]))<<24)|(((unsigned long)(Rx_Buffer_Pre[20]))<<16)|(((unsigned long)(Rx_Buffer_Pre[21]))<<8)|Rx_Buffer_Pre[22];
Pf_data_F=(float)(Pf_data*0.001);
printf("功率因数:%.3lf \r\n",Pf_data_F); //串口一来打印接受功率因数
CO2_data= (((unsigned long)(Rx_Buffer_Pre[23]))<<24)|(((unsigned long)(Rx_Buffer_Pre[24]))<<16)|(((unsigned long)(Rx_Buffer_Pre[25]))<<8)|Rx_Buffer_Pre[26];
CO2_data_F=(float)(CO2_data*0.0001);
printf("二氧化碳:%.4lf Kg\r\n",CO2_data_F);//串口一来打印接受二氧化碳
Temp_data= (((unsigned long)(Rx_Buffer_Pre[27]))<<24)|(((unsigned long)(Rx_Buffer_Pre[28]))<<16)|(((unsigned long)(Rx_Buffer_Pre[29]))<<8)|Rx_Buffer_Pre[30];
Temp_data_F=(float)(Temp_data*0.01);
printf("温度:%.2lf °C\r\n",Temp_data_F);//串口一来打印接受二氧化碳
HZ= (((unsigned long)(Rx_Buffer_Pre[31]))<<24)|(((unsigned long)(Rx_Buffer_Pre[32]))<<16)|(((unsigned long)(Rx_Buffer_Pre[33]))<<8)|Rx_Buffer_Pre[34];
HZ_F=(float)(HZ*0.01);
printf("赫兹:%.2lf HZ\r\n",HZ_F);//串口一来打印接受单相交流电的赫兹
DEBUG_LOG("==================================================================================");
USART3_RX_STA=0;
}
else printf("// CRC 校验错误\r\n");
}
}
else printf("\r\nreceive_finished标志位为0\r\n");
}
void IM266_clearBuf(void) //清空USART3_RX_BUF内存
{
int i;
for(i=0;i<37;i++)
Rx_Buffer_Pre[i]=0;
}
主函数
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
usart3_init(4800); //IM1266通讯串口
DEBUG_LOG("UART3初始化 [OK]");
while(1)
{
read_enable=1; //读数据使能
read_data(); //读IM1266数据-中断接收数据-使能完成标志位
delay_ms(2000); //等待中断传输
if(receive_finished)
{
Analysis_data();
receive_finished=0;
}
}
}
上图
用PC的效果:
串口调试的效果:
小程序演示的效果:
数据能正常能读取
感谢 良心不痛吗 关于IM1281B的代码,给了很大启发