第一步:TIME2定时器的初始化
#include “hk32f030m.h”
#include “hk32f030m_tim.h”
void time2_init() //初始化定时器
{
uint16_t PrescalerValue = 0;
PrescalerValue = (uint16_t) ((SystemCoreClock ) / 32000000) – 1;//配置频率为32M
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //打开TIM2的时钟
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //定义定时器配置结构体
NVIC_InitTypeDef NVIC_InitStructure; //定义中断向量结构体
TIM_TimeBaseStructure.TIM_Period = 10000; //溢出上限值
TIM_TimeBaseStructure.TIM_Prescaler = 31; //分频系数1-65535之间
//TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分频因子,外部时钟源才有用
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化定时器结构体
TIM_PrescalerConfig(TIM2, PrescalerValue, TIM_PSCReloadMode_Immediate);
/* TIM Interrupts enable */
//是否需要在此处增加一个清除定时器中断标志位的命令待定
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //开启定时计数器中断
/* TIM3 enable counter */
TIM_Cmd(TIM2, ENABLE); //使能计数器
//配置定时器的中断优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; //设置中断来源
NVIC_InitStructure.NVIC_IRQChannelPriority = 1; //设置优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
NVIC_Init(&NVIC_InitStructure); //初始化中断向量结构体
}
第二步:串口初始化
#include “gpio_init.h”
#include “hk32f030m.h”
#include “hk32f030m_usart.h”
#include “uart.h”
void uart_init(void)
{
USART_InitTypeDef m_usart;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
m_usart.USART_BaudRate = 9600;
m_usart.USART_HardwareFlowControl =
USART_HardwareFlowControl_None; //硬件流控制无
m_usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //工作模式收发一体
m_usart.USART_Parity = USART_Parity_No; //校验位无
m_usart.USART_StopBits = USART_StopBits_1; //停止位1位
m_usart.USART_WordLength = USART_WordLength_8b; //数据字长8位
USART_Init(USART1, &m_usart);
USART_Cmd(USART1, ENABLE);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //串口接收中断使能
//IRQ,此处是否需要定义结构体并初始化待定
NVIC_SetPriority(USART1_IRQn,0); //中断来源
NVIC_EnableIRQ(USART1_IRQn); //使能中断向量
}
void USART_SendByte(uint8_t ch)
{
while((USART1->ISR & USART_ISR_TXE) == 0);
USART1->TDR = ch;
}
void USART_SendStringLen(uint8_t *p,uint16_t len)
{
while(len–)
{
USART_SendByte(*(p++));
}
}
第三步:定时器中断处理程序和串口中断处理程序
void USART1_IRQHandler(void)
{
uint8_t ch_rx_test;
if((USART1->ISR & USART_ISR_RXNE) != 0)
{
//GPIO_SetBits(GPIOA,GPIO_Pin_2);
//USART_ITConfig(USART1, USART_IT_RXNE, DISABLE); //关闭串口接收中断
ch_rx_test = USART1->RDR; //RXNE auto clear at read after标志位在读取后自动清除
modbusa.rcbuf[modbusa.recount++] = ch_rx_test; //把数据存入接收缓冲数组
modbusa.timout = 0; //定时计数值清零
if(modbusa.recount == 1) //如果收到了第一个字节数据
{
modbusa.timrun = 1; //启动计数
}
}
//USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //打开串口接收中断
}
void TIM2_IRQHandler(void)
{
//GPIO_ResetBits(GPIOA,GPIO_Pin_2);
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
if(modbusa.timrun != 0) //判断是否启动计数
{
modbusa.timout++; //计数值累加
if(modbusa.timout >= 8) //判断累加是否达到时间,就是判断两次串口接收数据的间隔时间
{
modbusa.timrun = 0; //结束计数
modbusa.reflag = 1; //收到一帧数据的标志位置一,开始处理数据
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除定时器中断标志位
}
}
第四步:modbus处理程序
1、头文件
#ifndef __modbus_H
#define __modbus_H
#endif
#include “hk32f030m.h”
typedef struct
{
uint8_t myadd; //本机地址
uint8_t rcbuf[64]; //接收缓冲区
uint16_t timout; //数据接收两个字节的间隔时间计数
uint8_t recount; //接收到的字节个数
uint8_t timrun; //定时器是否开始计时标志
uint8_t reflag; //收到一帧标志
uint8_t sendbuf[64]; //发送缓冲区
}MODBUS;
extern MODBUS modbusa; //定义全局变量结构体
void modbus_event(void);
void modbud_fun3(void);
void modbud_fun6(void);
2、c文件
#include “hk32f030m.h”
#include “modbus.h”
#include “CRC16.h”
#include “uart.h”
MODBUS modbusa;
void modbus_event(void)
{
modbusa.myadd = 1;
uint16_t crc;
uint16_t rccrc;
if(modbusa.reflag == 0) //判断帧标志位,如果为0则直接退出函数
{
return;
}
crc = MB_CRC16(&modbusa.rcbuf[0],modbusa.recount-2); //计算校验码
rccrc = modbusa.rcbuf[modbusa.recount-2]*256+modbusa.rcbuf[modbusa.recount-1]; //接收的校验码
if(crc == rccrc) //校验码比较
{
if(modbusa.rcbuf[0] == modbusa.myadd) //从机地址比较
{
//USART_SendByte(0X55);
//USART_SendByte(modbusa.rcbuf[1]);
switch(modbusa.rcbuf[1]) //功能码识别
{
case 0: break;
case 1: break;
case 2: break;
case 3: modbud_fun3(); break; //执行3号功能码响应函数
case 6: modbud_fun6(); break; //执行6号功能码响应函数
case 7: break;
case 16: break;
}
}
else if(modbusa.rcbuf[0] == 0) //广播地址无响应
{
}
}
modbusa.recount = 0; //接收字节数清零
modbusa.reflag = 0; //帧标志位清零
}
void modbud_fun3(void)
{
extern uint16_t reg[];
uint16_t regadd;
uint16_t reglen;
uint16_t byte;
uint16_t i,j;
uint16_t crc;
regadd = modbusa.rcbuf[2]*256+modbusa.rcbuf[3]; //计算要读取的寄存器起始地址
reglen = modbusa.rcbuf[4]*256+modbusa.rcbuf[5]; //计算要读取的寄存器数量
i = 0;
modbusa.sendbuf[i++] = modbusa.myadd; //本机地址
modbusa.sendbuf[i++] = 0x03; //功能码
byte = reglen*2; //计算要返回的字节数
//modbusa.sendbuf[i++] = byte/256; //除以256相当于右移8位,取高8位来使用
modbusa.sendbuf[i++] = byte%256; //字节数写入发送缓冲区,取余256相当于直接用低8位
for(j=0;j<reglen;j++) //读取的数据循环写入发送缓冲区
{
modbusa.sendbuf[i++] = reg[regadd+j]/256;
modbusa.sendbuf[i++] = reg[regadd+j]%256;
}
crc = MB_CRC16(modbusa.sendbuf,i); //计算校验码
modbusa.sendbuf[i++] = crc/256; //校验码写入发送缓冲区
modbusa.sendbuf[i++] = crc%256;
for(j=0;j<i;j++) //循环发送数据到串口
{
USART_SendByte(modbusa.sendbuf[j]);
}
}
void modbud_fun6(void)
{
extern uint16_t reg[];
uint16_t regadd;
uint16_t val;
uint16_t i,j;
uint16_t crc;
i = 0;
regadd = modbusa.rcbuf[2]*256+modbusa.rcbuf[3]; //计算要写入的寄存器起始地址
val = modbusa.rcbuf[4]*256+modbusa.rcbuf[5]; //计算要修改后的值
reg[regadd] = val; //修改本机地址的值
modbusa.sendbuf[i++] = modbusa.myadd; //本机地址
modbusa.sendbuf[i++] = 0x06; //功能码
modbusa.sendbuf[i++] = regadd/256; //除以256相当于右移8位,取高8位来使用
modbusa.sendbuf[i++] = regadd%256; //字节数写入发送缓冲区,取余256相当于直接用低8位
modbusa.sendbuf[i++] = val/256; //高位值
modbusa.sendbuf[i++] = val%256; //低位值
crc = MB_CRC16(modbusa.sendbuf,i); //计算校验码
modbusa.sendbuf[i++] = crc/256; //校验码写入发送缓冲区
modbusa.sendbuf[i++] = crc%256;
for(j=0;j<i;j++) //循环发送数据到串口
{
USART_SendByte(modbusa.sendbuf[j]);
}
}
第五步:CRC16校验码计算程序
#include “hk32f030m.h”
uint16_t MB_CRC16(uint8_t *_pushMsg,uint8_t _usDataLen)
{
// CRC 高位字节值表
static const uint8_t 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
} ;
// CRC 低位字节值表
static const uint8_t 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
};
uint8_t uchCRCHi = 0xFF;
uint8_t uchCRCLo = 0xFF;
uint16_t uIndex;
while(_usDataLen–)
{
uIndex = uchCRCLo ^ *_pushMsg++;
uchCRCLo = uchCRCHi^auchCRCHi[uIndex];
uchCRCHi = auchCRCLo[uIndex];
}
return (uchCRCHi<<8|uchCRCLo);
}
第六步:主程序
#include “hk32f030m.h”
#include “hk32f030m_gpio.h”
#include “uart.h”
#include “string.h”
#include “gpio_init.h”
#include “hk32f030m_usart.h”
#include “modbus.h”
#include “time2.h”
static void ledGpioToggle(void);
static void softWareDelay(void);
#define X0 GPIO_Pin_7
#define X1 GPIO_Pin_6
#define Y0 GPIO_Pin_4
#define RUNLED GPIO_Pin_2
uint16_t reg[100];
int main(void)
/* Infinite loop */
{
gpio_init();
uart_init();
softWareDelay();
time2_init();
while (1)
{
modbus_event();
if(GPIO_ReadInputDataBit(GPIOC,X0)==0)
{
GPIO_SetBits(GPIOD,Y0);
reg[1]++;
}
if(GPIO_ReadInputDataBit(GPIOC,X1)==0)
{
GPIO_ResetBits(GPIOD,Y0);
reg[0]++;
}
}
GPIO_SetBits(GPIOA,RUNLED); //这句指令永远执行不到,警告
}
static void ledGpioToggle(void)
{
GPIOC->ODR ^= GPIO_Pin_7;
}
static void softWareDelay(void)
{
uint16_t i;
uint16_t j;
for(i=0;i<500;i++)
{
for(j=0;j<1000;j++)
{
__NOP();
}
}
}






不懂哦