搜档网
当前位置:搜档网 › 用stm32库函数编写的modbus源代码

用stm32库函数编写的modbus源代码

用stm32库函数编写的modbus源代码
用stm32库函数编写的modbus源代码

用stm32库函数编写的modbus源代码

说在前面的话:

1.请勿盲目抄袭。这个协议使用了一个定时器,所以在别处请不要再使用,如果定时器不够用,可以做虚拟定时器。也就是采用一个物理的定时器产生时基。在这个定时器的中断函数中可以给相应的多个定时器自加1.每个虚拟定时器可以用两个变量分别控制打开关闭,和计时。这个已经试验通过了可行的。其实就跟我们使用物理的定时器一样,只不过物理的定时器是用晶振产生时基。

2.这段代码已经调试通过了,也硬件试验过,没有问题,如果你出现问题了,看看你在主函数的的各种基本配置有没有完成。如果要使用06和10号功能,你还需要在主函数中建立一个100个元素的数组,每个元素是16位。

3.写这个文档的时候,这个协议已经是半年前完成的了。所以有些东西记得不是很清楚了,如果说错了,请以实际为准。只是不想让这份代码死在电脑中了,所以才想起来要拿出来分享,支持开源精神。

4.如果实在实在是没有弄出来,请联系我,可以共同交流,我的邮箱:xiaozuoadamszju@https://www.sodocs.net/doc/e116868052.html,

#include"stm32f10x.h"

/* 此Modbus协议暂时只支持RTU模式,只支持作为Modbus从设备。

暂时支持的功能码(16进制)如下表所示:

01.读线圈状态(读多个输出位的状态,有效地位为0-31)

02.读输入位状态(读多个输入位的状态,有效地位为0-31)

03.读保持寄存器(读多个保持寄存器的数值,有效地位为0-99)

04.读输入寄存器(读多个输入寄存器的数值,有效地址为0-1)

05.强制单个线圈(强制单个输出位的状态,有效地位为0-31)

06.预制单个寄存器(设定一个寄存器的数值,有效地址为0-99)

0F.强制多个线圈(强制多个输出位的状态,有效地址为0-31)

10.预制多个寄存器(设定多个寄存器的数值,有效地址为0-99)

暂时支持的错误代码为:

01 不合法功能代码从机接收的是一种不能执行功能代码。发出查询命令后,该代码指示无程序功能。(不支持的功能代码)

02 不合法数据地址接收的数据地址,是从机不允许的地址。(起始地址不在有效范围内)

03 不合法数据查询数据区的值是从机不允许的值。(在起始地址的基础上,这个数量是不合法的)

供用户调用的函数有:

1.void ModInit(u8 Id);//用于Modbus初始化,在函数调用前,必须初始化函数,用于Main函数中

2.void ModRcv(void);//用于modbus信息接收,放在串口接收中断

3.void ModSend(void);//用于modbus信息接收,放在串口发送中断

例如:void USART1_IRQHandler(void) //USART1中断

{

if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)

{

voidModRcv(void);

……

……

……

}

if(USART_GetITStatus(USART1,USART_IT_TC)!=RESET)

{

void ModSend(void);//用于modbus信息接收

……

……

……

}

}

*/

//modbus用通讯参数

u8 Tim_Out;//大于3.5个字符时间,保守取3ms (波特率9600的时候大约2点几毫秒)

u8 Rcv_Complete;//一帧是否已经接受完成

u8 Send_Complete;//一帧是否已经发送完成

u8 Com_busy;//通讯繁忙,表示上一帧还未处理结束

u8 Rcv_Buffer[210];//用来存放接收到的完整的一帧数据(第一个字节用来存放接收到的有效字节数,也就是数组中的有效字节数)

u8 Send_Buffer[210];//用来存放待发送的完整的一帧数据(第一个字节用来存放

待发送的有效字节数,也就是数组中的有效字节数)

u8 Rcv_Data;//用来存放接收的一个字节

u8 Send_Data;//用来存放要发送的一字节

u8 Mod_Id;//用来标志作为从站的站号

u8 Rcv_Num;//用来表示接收的一帧的有效字节数(从功能码到CRC校验)u8 Send_Num;//用来表示待发送的一帧的字节数

u8 *PointToRcvBuf;//用来指向接收的数据缓存

u8 *PointToSendBuf;//用来指向带发送的数据缓存

u8 Comu_Busy;//用来表示能否接收下一帧数据

u8HaveMes;

extern u16 HoldReg[100];

//CRC校验查表用参数

/* CRC 高位字节值表*/

static u8 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 u8 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

} ;

//声明modbus的函数

void ModInit(u8 Id);//用于Modbus初始化,参数Id为站号(1-255)void ModRcv(void);//用于modbus信息接收

void ModSend(void);//用于modbus信息接收

void MessageHandle(u8 *pointer_in,u8 *pointer_out);//处理收到的信息帧void ReadOutputBit(u8 *pointer_1,u8 *pointer_2);//读线圈

void ReadInputBit(u8 *pointer_1,u8 *pointer_2);//读输入位

void ReadHoldingReg(u8 *pointer_1,u8 *pointer_2);//读保持寄存器

void ReadInputReg(u8 *pointer_1,u8 *pointer_2);//读输入寄存器

void ForceSingleCoil(u8 *pointer_1,u8 *pointer_2);//强制单个线圈

void PresetSingleReg(u8 *pointer_1,u8 *pointer_2);//预制单个寄存器void ForceMulCoil(u8 *pointer_1,u8 *pointer_2);//强制多个线圈

void PresetMulReg(u8 *pointer_1,u8 *pointer_2);//预制多个寄存器

void ErrorHandle(u8 Mode,u8 *Pointer);//错误信息帧处理

u16 CRC16(u8 *puchMsgg,u8 usDataLen);//用于计算CRC校验码

/* 函数功能:用于Modbus初始化

函数输入:Id为Modbus站号。

函数输出:无。*/

voidModInit(u8 Id)

{

//modbus参数初始化

PointToRcvBuf=Rcv_Buffer;

PointToSendBuf=Send_Buffer;

Send_Num=1;//发送的数据顺序(输出数组的第几个数)

Mod_Id=Id;//站号设置

Rcv_Buffer[1]=Mod_Id;

Send_Buffer[1]=Mod_Id;

Comu_Busy=0;

}

/* 函数功能:用于Modbus信息接收

函数输入:无。

函数输出:无。*/

voidModRcv(void)

{

HaveMes=1;//表示接收到了信息

Rcv_Data=USART_ReceiveData(USART1);

if(Comu_Busy!=1)//如果不忙,可以接收下一帧信息

{

TIM_Cmd(TIM2, DISABLE);

TIM_SetCounter(TIM2,0);

if((Tim_Out!=0)&&(Rcv_Data==Mod_Id))//如果间隔时间超过了3.5个字符,同时接受的字节和自己的站号一致,则认为接收开始

{

Rcv_Complete=0;//表示数据帧接收开始

Rcv_Num=0;//接收数据个数初始化

Rcv_Num++;//同时个数加一

}

if((0==Tim_Out)&&(0==Rcv_Complete))//如果处于接收一帧的正常过程中

{

if(Rcv_Num<100)

{

Rcv_Buffer[Rcv_Num+1]=Rcv_Data;//将数据放入接收数组中

Rcv_Num++;//同时个数加一

}

else

{

Rcv_Complete=1;

Comu_Busy=1;

Rcv_Buffer[0]=Rcv_Num;

*(PointToSendBuf+2)=*(PointToRcvBuf+2);//获取功能码

ErrorHandle(6,PointToSendBuf);//表示超出了字节数(从机设备忙碌)

Rcv_Num=0;

}

}

Tim_Out=0;

TIM_Cmd(TIM2, ENABLE);//开启4.5ms计时(三个半字符的保守估计)

}

}

/* 函数功能:用于Modbus信息发送

函数输入:无。

函数输出:无。

*/

voidModSend(void)

{

Send_Data=*(PointToSendBuf+Send_Num);

USART_SendData(USART1,Send_Data);

Send_Num++;

if(Send_Num>(*PointToSendBuf))//发送已经完成

{

Comu_Busy=0;

*PointToSendBuf=0;

Rcv_Num=0;

Send_Num=1;

//启动数据发送

USART_ITConfig(USART1, USART_IT_TC, DISABLE);//关闭数据发送中断

}

}

/* 函数功能:Modbus专用定时器(TIM2)

函数输入:无。

函数输出:无。*/ void TIM2_IRQHandler(void)

{

if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源

{

TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源

Tim_Out=1;

TIM_Cmd(TIM2,DISABLE);

TIM_SetCounter(TIM2,0);

Rcv_Complete=1;

Rcv_Buffer[0]=Rcv_Num;

if(HaveMes!=0&&Rcv_Num>4)

{

Comu_Busy=1;

MessageHandle(PointToRcvBuf,PointToSendBuf);

}

}

}

/* 函数功能:CRC校验用函数

函数输入:puchMsgg是要进行CRC校验的消息,usDataLen是消息中字节数

函数输出:计算出来的CRC校验码。*/

u16 CRC16(u8 *puchMsgg,u8 usDataLen)//puchMsgg是要进行CRC校验的消息,usDataLen是消息中字节数

{

u8 uchCRCHi = 0xFF ; /* 高CRC字节初始化*/

u8 uchCRCLo = 0xFF ; /* 低CRC 字节初始化*/

u8 uIndex ; /* CRC循环中的索引*/

while (usDataLen--) /* 传输消息缓冲区*/

{

uIndex = uchCRCHi ^ *puchMsgg++ ; /* 计算CRC */

uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex] ;

uchCRCLo = auchCRCLo[uIndex] ;

}

return ((uchCRCHi<< 8) | uchCRCLo) ;

}

/* 函数功能:对输入的信息帧进行处理,按照功能码不同,调用不同的函数处理

函数输入:两个指针,pointer_1指向用来存放输入信息帧的数组,

pointer_2用来指向存放输出信息帧的数组(两个数组的第一个元素都用来存放信息帧的有效字节个数)

后面的元素按照Modbus协议组织。

函数输出:无。*/

voidMessageHandle(u8 *pointer_in,u8 *pointer_out)

{

u16 CalKey;//计算出来的校验值

u16 RcvKey;//接收到的校验值

HaveMes=0;//清除信息位

//获取接收到的校验值

RcvKey=(u16)*(pointer_in+(*pointer_in-1));

RcvKey=RcvKey<<8;

RcvKey=RcvKey|(u16)*(pointer_in+(*pointer_in));

CalKey=CRC16(pointer_in+1,*pointer_in-2);

if(CalKey==RcvKey)

{

switch(*(pointer_in+2))//第二个字节为功能码

{

case 0x01:ReadOutputBit(pointer_in,pointer_out);//读输出线圈

break;

case 0x02:ReadInputBit(pointer_in,pointer_out);//读输入位

break;

case 0x03:ReadHoldingReg(pointer_in,pointer_out);//读保持寄存器break;

case 0x04:ReadInputReg(pointer_in,pointer_out);//读输入寄存器

break;

case 0x05:ForceSingleCoil(pointer_in,pointer_out);//强制单个线圈状态

break;

case 0x06:PresetSingleReg(pointer_in,pointer_out);//预制单个寄存器break;

case 0x0F:ForceMulCoil(pointer_in,pointer_out);//强制多个线圈

break;

case 0x10:PresetMulReg(pointer_in,pointer_out);//预制多个寄存器break;

default:

{

*(pointer_out+2)=*(pointer_in+2);//获取功能码

ErrorHandle(1,pointer_out);//功能码错误

}

break;

}

}

else

{

Comu_Busy=0;

}

}

/* 函数功能:读取线圈状态

函数输入:两个指针,pointer_1指向用来存放输入信息帧的数组,

pointer_2用来指向存放输出信息帧的数组(两个数组的第一个元素都用来存放信息帧的有效字节个数)

后面的元素按照Modbus协议组织。

函数输出:无。*/

void ReadOutputBit(u8 *pointer_1,u8 *pointer_2)//pointer_1用作输入,pointer_2用作输出

{

u16 Address=0;//待读取线圈起始地址(GPIO_X,X为A,B两个端口,每个端口16位,对应地址0——31)

u16 Num=0;//要读取的线圈个数

u8 Byte=0;//要读取的线圈个数总共占用的字节数;

u32 PortTemp;//用来存放从端口取过来的数据

u16 ReadData=0;//用来临时存放从端口读来的数据

u16 SendKey;//要发送数据的校验值

Address=(u16)(*(pointer_1+3))*256+(*(pointer_1+4));//先得到线圈地址

Num=(u16)(*(pointer_1+5))*256+(*(pointer_1+6));//先得到要读取的线圈个数*(pointer_2+2)=0x01;//第三个字节为功能码

if(*(pointer_1)==8) //如果接收到的字节数不是8个,就是一个错误帧{

if(Address<32) //只要地址小于32,就是合法地址

{

if(Address+Num<=32&&Num>0) //只要地址加数量大于0小于80,就是合法数量

{

//用于for循环

u8i;

u8 j;

Byte=Num/8;

if(Num%8!=0)

Byte++;//如果不整除的话,加一个字节,剩余的高位补零*(pointer_2+3)=Byte;//第四个字节为要发送的个数

*(pointer_2)=1+1+1+Byte+2;//有效字节个数等于丛机地址+功能码+字节个数+线圈信息+CRC校验

//将端口C和D的数据预先读入到临时的数据缓存中

ReadData=GPIO_ReadOutputData(GPIOD);

PortTemp=(u32)(ReadData);

PortTemp=PortTemp<<16;

ReadData=GPIO_ReadOutputData(GPIOC);

PortTemp=PortTemp|(u32)(ReadData);

//将PortTemp中的数据处理成需要的位数,再装入输出数据缓存中

PortTemp=PortTemp<<(31-(Address+Num-1));

PortTemp=PortTemp>>((31-(Address+Num-1))+Address);

//将数据一个字节一个字节装到发送数据缓存数组中

for(i=4,j=Byte;j>0;j--,i++)

{

*(pointer_2+i)=(u8)(PortTemp&0x00FF);//截取一个字节的长度,存放起来

PortTemp=PortTemp>>8;//再将数据向右移动8位

}

//写入校验码

SendKey=CRC16(pointer_2+1,*pointer_2-2);

//将计算出来的校验码装入输出数据缓存中

*(pointer_2+(*pointer_2-1))=(u8)(SendKey>>8);

*(pointer_2+(*pointer_2))=(u8)(SendKey&0x00FF);

//启动数据发送

USART_ITConfig(USART1, USART_IT_TC, ENABLE);//开启数据发送中断

}

else

{

ErrorHandle(3,pointer_2);//错误读取数量

}

}

else

{

ErrorHandle(2,pointer_2);//错误起始地址

}

}

else

{

Comu_Busy=0;

}

}

/* 函数功能:读取输入状态

函数输入:两个指针,pointer_1指向用来存放输入信息帧的数组,

pointer_2用来指向存放输出信息帧的数组(两个数组的第一个元素都用来存放信息帧的有效字节个数)

后面的元素按照Modbus协议组织。

函数输出:无。*/

void ReadInputBit(u8 *pointer_1,u8 *pointer_2)//pointer_1用作输入,pointer_2用作输出

{

u16 Address=0;//待读取输入位起始地址(GPIO_X,X为C,D两个端口,每个端口16位,对应地址0-31)

u16 Num=0;//要读取的输入位个数

u8 Byte=0;//要读取的输入位个数总共占用的字节数;

u32 PortTemp;//用来存放从端口取过来的数据,临时计算用

u16 ReadData=0;//用来临时存放从端口读来的数据

u16 SendKey;//要发送数据的校验值

Address=(u16)(*(pointer_1+3))*256+(*(pointer_1+4));//先得到输入位地址

Num=(u16)(*(pointer_1+5))*256+(*(pointer_1+6));//先得到要读取的输入位个数

*(pointer_2+2)=0x02;//第三个字节为功能码

if(*(pointer_1)==8) //如果接收到的字节数不是8个,就是一个错误帧{

if(Address<32) //只要地址小于32,就是合法地址

{

if(Address+Num<=32&&Num>0) //只要地址加数量大于0小于80,就是合法数量

{

//用于for循环

u8i;

u8 j;

Byte=Num/8;

if(Num%8!=0)

Byte++;//如果不整除的话,加一个字节,剩余的高位补零*(pointer_2+3)=Byte;//第四个字节为要发送的个数

*(pointer_2)=1+1+1+Byte+2;//有效字节个数等于丛机地址+功能码+字节个数+输入位信息+CRC校验

//将端口A和B的数据预先读入到临时的数据缓存中

ReadData=GPIO_ReadInputData(GPIOB);

PortTemp=(u32)(ReadData);

PortTemp=PortTemp<<16;

ReadData=GPIO_ReadInputData(GPIOA);

PortTemp=PortTemp|(u32)(ReadData);

//将PortTemp中的数据处理成需要的位数,再装入输出数据缓存中

PortTemp=PortTemp<<(31-(Address+Num-1));

PortTemp=PortTemp>>((31-(Address+Num-1))+Address);

//将数据一个字节一个字节装到发送数据缓存数组中

for(i=4,j=Byte;j>0;j--,i++)

{

*(pointer_2+i)=(u8)(PortTemp&0x00FF);//截取一个字节的长度,存放起来

PortTemp=PortTemp>>8;//再将数据向右移动8位

}

//写入校验码

SendKey=CRC16(pointer_2+1,*pointer_2-2);

//将计算出来的校验码装入输出数据缓存中

*(pointer_2+(*pointer_2-1))=(u8)(SendKey>>8);

*(pointer_2+(*pointer_2))=(u8)(SendKey&0x00FF);

//启动数据发送

USART_ITConfig(USART1, USART_IT_TC, ENABLE);//开启数据发送中断

}

else

{

ErrorHandle(3,pointer_2);//错误读取数量

}

}

else

{

ErrorHandle(2,pointer_2);//错误起始地址

}

}

else

{

Comu_Busy=0;

}

}

/* 函数功能:读取保持寄存器

函数输入:两个指针,pointer_1指向用来存放输入信息帧的数组,

pointer_2用来指向存放输出信息帧的数组(两个数组的第一个元素都用来存放信息帧的有效字节个数)

后面的元素按照Modbus协议组织。

函数输出:无。

*/

void ReadHoldingReg(u8 *pointer_1,u8 *pointer_2)//pointer_1用作输入,pointer_2

用作输出

{

u16 Address=0;//待读取寄存器起始地址(HoldReg[i],i为0-99对应地址从0到99)

u16 Num=0;//要读取的寄存器个数

u16 SendKey;//要发送数据的校验值

Address=(u16)(*(pointer_1+3))*256+(*(pointer_1+4));//先得到寄存器起始地址Num=(u16)(*(pointer_1+5))*256+(*(pointer_1+6));//先得到要读取的寄存器个数

*(pointer_2+2)=0x03;//第三个字节为功能码

if(*(pointer_1)==8) //如果接收到的字节数不是8个,就是一个错误帧

{

if(Address<100) //只要地址小于100,就是合法地址

{

if(Address+Num<=100&&Num>0) //只要地址加数量大于0小于100,就是合法数量

{

//用于for循环

u8i;

u8 j;

*(pointer_2+3)=Num*2;//第四个字节为要发送的字节个数

*(pointer_2)=1+1+1+Num*2+2;//有效字节个数等于丛机地址+功能码+字节个数+寄存器信息+CRC校验

STM32固件库的学习(重要,要常看)

1. stm32的编程中,在stdperiph_drive中添加的misc.c文件是干什么用的啊? 因为STM32 V3.5版本的库函数中没有原来版本中单独对于NVIC(中断向量嵌套)的外设驱动,把NVIC的外设驱动放在了misc.c中,实际上是代替原来的stm32f10x_nvic.c。 2. STM32F10XXX V 3.5标准外设库文件夹描述 标准外设库的第一部分是CMSIS 和STM32F10x_StdPeriph_Driver,CMSIS 是独立于供应商的Cortex-M处理器系列硬件抽象层,为芯片厂商和中间件供应商提供了简单的处理器软件接口,简化了软件复用工作,降低了Cortex-M上操作系统的移植难度,并减少了新入门的微控制器开发者的学习曲线和新产品的上市时间。 STM32F10x_StdPeriph_Driver则包括了分别对应包括了所有外设对应驱动函数,这些驱动函数均使用C语言编写,并提供了统一的易于调用的函数接口,供开发者使用。Project 文件夹中则包括了ST官方的所有例程和基于不同编译器的项目模板,这些例程是学习和使用STM32的重要参考。Utilities包含了相关评估板的示例程序和驱动函数,供使用官方评估板的开发者使用,很多驱动函数同样可以作为学习的重要参考。 3.文件功能说明

4.CMSIS文件夹结构

在实际开发过程中,根据应用程序的需要,可以采取2种方法使用标准外设库

(StdPeriph_Lib): (1)使用外设驱动:这时应用程序开发基于外设驱动的API(应用编程接口)。用户只需要配置文件”stm32f10x_conf.h”,并使用相应的文件”stm32f10x_ppp.h/.c”即可。 (2) 不使用外设驱动:这时应用程序开发基于外设的寄存器结构和位定义文件。 5. STM32F10XXX标准外设库的使用 标准外设库中包含了众多的变量定义和功能函数,如果不能了解他们的命名规范和使用规律将会给编程带来很大的麻烦,本节将主要叙述标准外设库中的相关规范,通过这些规范的学习可以更加灵活的使用固件库,同时也将极大增强程序的规范性和易读性,同时标准外设库中的这种规范也值得我们在进行其他相关的开发时使用和借鉴。 a.缩写定义 标准外设库中的主要外设均采用了缩写的形式,通过这些缩写可以很容易的辨认对应的外设。

stm32入门C语言详解

阅读flash:芯片内部存储器flash操作函数我的理解——对芯片内部flash进行操作的函数,包括读取,状态,擦除,写入等等,可以允许程序去操作flash上的数据。 基础应用1,FLASH时序延迟几个周期,等待总线同步操作。推荐按照单片机系统运行频率,0—24MHz时,取Latency=0;24—48MHz时,取Latency=1;48~72MHz时,取Latency=2。所有程序中必须的 用法:FLASH_SetLatency(FLASH_Latency_2); 位置:RCC初始化子函数里面,时钟起振之后。 基础应用2,开启FLASH预读缓冲功能,加速FLASH的读取。所有程序中必须的 用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); 位置:RCC初始化子函数里面,时钟起振之后。 3、阅读lib:调试所有外设初始化的函数。 我的理解——不理解,也不需要理解。只要知道所有外设在调试的时候,EWRAM需要从这个函数里面获得调试所需信息的地址或者指针之类的信息。 基础应用1,只有一个函数debug。所有程序中必须的。 用法:#ifdef DEBUG debug(); #endif 位置:main函数开头,声明变量之后。 4、阅读nvic:系统中断管理。 我的理解——管理系统内部的中断,负责打开和关闭中断。 基础应用1,中断的初始化函数,包括设置中断向量表位置,和开启所需的中断两部分。所有程序中必须的。 用法:void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; //中断管理恢复默认参数 #ifdef VECT_TAB_RAM //如果C/C++ Compiler\Preprocessor\Defined symbols中的定义了 VECT_TAB_RAM(见程序库更改内容的表格) NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //则在RAM调试 #else //如果没有定义VECT_TAB_RAM NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//则在Flash里调试 #endif //结束判断语句 //以下为中断的开启过程,不是所有程序必须的。 //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC优先级分组,方式。 //注:一共16个优先级,分为抢占式和响应式。两种优先级所占的数量由此代码确定, NVIC_PriorityGroup_x可以是0、1、2、3、4,分别代表抢占优先级有1、2、4、8、16个和响应优先级有16、8、4、2、1个。规定两种优先级的数量后,所有的中断级别必须在其中选择,抢占级别高的会打断其他中断优先执行,而响应级别高的会在其他中断执行完优先执行。 //NVIC_InitStructure.NVIC_IRQChannel = 中断通道名; //开中断,中断名称见函数库 //NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级 //NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //响应优先级 //NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //启动此通道的中断 //NVIC_Init(&NVIC_InitStructure); 中断初始化

stm32库函数解释

部分库函数简介 一、通用输入/输出(GPIO)--------------------------------------------------------------------------------------------3 二、外部中断/事件控制器(EXTI)-----------------------------------------------------------------------------------7 三、通用定时器(TIM)-------------------------------------------------------------------------------------------------9四:ADC寄存器------------------------------------------------------------------------25 五:备份寄存器(BKP)-------------------------------------------------------------------------------------------------33 六、DMA控制器(DMA)---------------------------------------------------------------37 七、复位和时钟设置(RCC)------------------------------------------------------------------------------------------41 八、嵌套向量中断控制器(NVIC)-----------------------------------------------------------------------------------49

理解__STM32__GPIO初始化__库函数

使用库函数进行STM32的产品开发无疑可以节省大量时间。下面将介绍GPIO 初始化所用到的库函数 以最常用的GPIO设备的初始化函数为例,如下程序段一: GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_Init(GPIOA,&GPIO_InitStructure) 这是一个在STM32的程序开发中经常使用到的GPIO初始化程序段,其功能是将GPIOA.4口初始化为推挽输出状态,并最大翻转速率为50MHz。下面逐一分解:l 首先是1,该语句显然定义了一个GPIO_InitTypeDef类型的变量,名为 GPIO_InitStructure,则找出GPIO_InitTypeDef的原型位于 “stm32f10x_gpio.h”文件,原型如下: typedef struct { u16GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; }GPIO_InitTypeDef; 由此可知GPIO_InitTypeDef是一个结构体类型同义字,其功能是定义一个结构体,该结构体有三个成员分别是u16类型的GPIO_Pin、 GPIOSpeed_TypeDef类型的GPIO_Speed和GPIOMode_TypeDef类型的 GPIO_Mode。继续探查GPIOSpeed_TypeDef和GPIOMode_TypeDef类型,在“stm32f10x_gpio.h”文件中找到对GPIOSpeed_TypeDef的定义: typedef enum { GPIO_Speed_10MHz=1, GPIO_Speed_2MHz, GPIO_Speed_50MHz }GPIOSpeed_TypeDef; 则可知GPIOSpeed_TypeDef枚举类型同一只,其功能是定义一个枚举类型变量,该变量可表示GPIO_Speed_10MHz、GPIO_Speed_2MHz和 GPIO_Speed_50MHz三个含义(其中GPIO_Speed_10MHz已经定义为1,读者必须知道GPIO_Speed_2MHz则依次被编译器赋予2,而GPIO_Speed_50MHz 为3)。 同样也在“stm32f10x_gpio.h”文件中找到对GPIOMode_TypeDef的定义: typedef enum

STM32固件库详解42324

STM32固件库详解 最近考试较多,教材编写暂停了一下,之前写了很多,只是每一章都感觉不是特别完整,最近把其中的部分内容贴出来一下,欢迎指正。本文内容基于我对固件库的理解,按照便于理解的顺序进行整理介绍,部分参考了固件库的说明,但是也基本上重新表述并按照我理解的顺序进行重新编写。我的目的很简单,很多人写教程只是告诉你怎么做,不会告诉你为什么这么做,我就尽量吧前因后果都说清楚,这是我的出发点,水平所限,难免有很大的局限性,具体不足欢迎指正。基于标准外设库的软件开发 STM32标准外设库概述 STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。该函数库还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了一个中间API,通过使用固件函数库,无需深入掌握底层硬件细节,开发者就可以轻松应用每一个外设。因此,使用固态函数库可以大大减少用户的程序编写时间,进而降低开发成本。每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。每个器件的开发都由一个通用API (application programming interface 应用编程界面)驱动,API对该驱动程序的结构,函数和参数名称都进行了标准化。

ST公司2007年10月发布了版本的固件库,MDK 之前的版本均支持该库。2008年6月发布了版的固件库,从2008年9月推出的MDK 版本至今均使用版本的固件库。以后的版本相对之前的版本改动较大,本书使用目前较新的版本。 使用标准外设库开发的优势 简单的说,使用标准外设库进行开发最大的优势就在于可以使开发者不用深入了解底层硬件细节就可以灵活规范的使用每一个外设。标准外设库覆盖了从GPIO到定时器,再到CAN、I2C、SPI、UART和ADC 等等的所有标准外设。对应的C源代码只是用了最基本的C编程的知识,所有代码经过严格测试,易于理解和使用,并且配有完整的文档,非常方便进行二次开发和应用。 STM32F10XXX标准外设库结构与文件描述 1. 标准外设库的文件结构 在上一小节中已经介绍了使用标准外设库的开发的优势,因此对标准外设库的熟悉程度直接影响到程序的编写,下面让我们来认识一下STM32F10XXX的标准外设库。STM32F10XXX的标准外设库经历众多的更新目前已经更新到最新的版本,开发环境中自带的标准外设库为版本,本书中以比较稳定而且较新的版本为基础介绍标准外设库的结构。

献给新手:解析STM32的库函数

意法半导体在推出STM32微控制器之初,也同时提供了一套完整细致的固件开发包,里面包含了在STM32开发过程中所涉及到的所有底层操作。通过在程序开发中引入这样的固件开发包,可以使开发人员从复杂冗余的底层寄存器操作中解放出来,将精力专注应用程序的开发上,这便是ST推出这样一个开发包的初衷。 但这对于许多从51/AVR这类单片机的开发转到STM32平台的开发人员来说,势必有一个不适应的过程。因为程序开发不再是从寄存器层次起始,而要首先去熟悉STM32所提供的固件库。那是否一定要使用固件库呢?当然不是。但STM32微控制器的寄存器规模可不是常见的8位单片机可以比拟,若自己细细琢磨各个寄存器的意义,必然会消耗相当的时间,并且对于程序后续的维护,升级来说也会增加资源的消耗。对于当前“时间就是金钱”的行业竞争环境,无疑使用库函数进行STM32的产品开发是更好的选择。本文将通过一个简单的例子对STM32的库函数做一个简单的剖析。 以最常用的GPIO设备的初始化函数为例,如下程序段一: GPIO_InitTypeDef GPIO_InitStructure; 1 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; 2 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 3 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 4 GPIO_Init(GPIOA , &GPIO_InitStructure 5 这是一个在STM32的程序开发中经常使用到的GPIO初始化程序段,其功能是将GPIOA.4口初始化为推挽输出状态,并最大翻转速率为50MHz。下面逐一分解: 首先是1,该语句显然定义了一个GPIO_InitTypeDef类型的变量,名为GPIO_InitStructure,则找出GPIO_InitTypeDef的原型位于“stm32f10x_gpio.h” 文件,原型如下: typedef struct { u16 GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; }GPIO_InitTypeDef; 由此可知GPIO_InitTypeDef是一个结构体类型同义字,其功能是定义一个结构体,该结构体有三个成员分别是u16类型的GPIO_Pin、 GPIOSpeed_TypeDef 类型的GPIO_Speed和GPIOMode_TypeDef 类型的 GPIO_Mode。继续探查GPIOSpeed_TypeDef和GPIOMode_TypeDef类型,在“stm32f10x_gpio.h”文件中找到对GPIOSpeed_TypeDef的定义: typedef enum { GPIO_Speed_10MHz = 1,

STM32F4库函数笔记

(1)GPIO_Mode_AIN 模拟输入 (2)GPIO_Mode_IN_FLOATING 浮空输入 (3)GPIO_Mode_IPD 下拉输入 (4)GPIO_Mode_IPU 上拉输入 (5)GPIO_Mode_Out_OD 开漏输出 (6)GPIO_Mode_Out_PP 推挽输出 (7)GPIO_Mode_AF_OD 复用开漏输出 (8)GPIO_Mode_AF_PP 复用推挽输出 平时接触的最多的也就是推挽输出、开漏输出、上拉输入这三种 推挽输出:可以输出高,低电平,连接数字器件; 开漏输出:输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行,一般来说,开漏是用来连接不同电平的器件,匹配电平用的,因为开漏引脚不连接外部的上拉电阻时,只能输出低电平。 浮空输入:由于浮空输入一般多用于外部按键输入,结合图上的输入部分电路,我理解为浮空输入状态下,IO的电平状态是不确定的,完全由外部输入决定,如果在该引脚悬空的情况下,读取该端口的电平是不确定的。 GPIO GPIO_Init函数初始化 { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);//使能GPIOF时钟 //GPIOF9,F10初始化设置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;//LED0和LED1对应IO口 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉 GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化GPIOF9,F10 } 2个读取输入电平函数: uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 作用:读取某个GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。 例如: GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);//读取GPIOA.5的输入电平 uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx); 作用:读取某组GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。 例如: GPIO_ReadInputData(GPIOA);//读取GPIOA组中所有io口输入电平 2个读取输出电平函数: uint8_t GPIO_ReadOutputDataBit (GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 作用:读取某个GPIO的输出电平。实际操作的是GPIO_ODR寄存器。 例如:

STM32固件库详解

STM32固件库详解 https://www.sodocs.net/doc/e116868052.html,/emouse/archive/2011/11/29/2268441.html 1.1 基于标准外设库的软件开发 1.1.1 STM32标准外设库概述 STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。该函数库还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了一个中间API,通过使用固件函数库,无需深入掌握底层硬件细节,开发者就可以轻松应用每一个外设。因此,使用固态函数库可以大大减少用户的程序编写时间,进而降低开发成本。每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。每个器件的开发都由一个通用API (application programming interface 应用编程界面)驱动,API对该驱动程序的结构,函数和参数名称都进行了标准化。 ST公司2007年10月发布了V1.0版本的固件库,MDK ARM3.22之前的版本均支持该库。2008年6月发布了V2.0版的固件库,从2008年9月推出的MDK ARM3.23版本至今均使用V2.0版本的固件库。V3.0以后的版本相对之前的版本改动较大,本书使用目前较新的V3.4版本。 1.1.2 使用标准外设库开发的优势 简单的说,使用标准外设库进行开发最大的优势就在于可以使开发者不用深入了解底层硬件细节就可以灵活规范的使用每一个外设。标准外设库覆盖了从GPIO到定时器,再到CAN、I2C、SPI、UART和ADC等等的所有标准外设。对应的C源代

stm32启动文件详解

STM32启动文件详解 一、启动文件的作用 1.初始化堆栈指针SP; 2.初始化程序计数器指针PC; 3.设置堆、栈的大小; 4.设置异常向量表的入口地址; 5.配置外部SRAM作为数据存储器(这个由用户配置,一般的开发板可没有外部SRAM); 6.设置C库的分支入口__main(最终用来调用main函数); 7.在版的启动文件还调用了在文件中的SystemIni()函数配置系统时钟。

二、汇编指令

三、启动代码 ----- 栈 Stack_Size EQU 0x00000400 ; 栈的大小 AREA STACK, NOINIT, READWRITE,ALIGN=3 Stack_Mem SPACE Stack_Size ; 分配栈空间 __initial_sp ; 栈的结束地址(栈顶地址) 分配名为STACK,不初始化,可读可写,8(2^3)字节对齐的1KB空间。 栈:局部变量,函数形参等。栈的大小不能超过内部SRAM大小。 AREA:汇编一个新的代码段或者数据段。STACK段名,任意命名;NOINIT表示不初始化;READWRITE可读可写;ALIGN=3(2^3= 8字节对齐)。 __initial_sp紧挨了SPACE放置,表示栈的结束地址,栈是从高往低生长,结束地址就是栈顶地址。

----- 堆 Heap_Size EQU 0x00000200 ; 堆的大小(512Bytes) AREA HEAP, NOINIT, READWRITE,ALIGN=3 __heap_base ; 堆的起始地址 Heap_Mem SPACE Heap_Size ; 分配堆空间 __heap_limit ; 堆的结束地址 分配名为HEAP,不初始化,可读可写,8(2^3)字节对齐的512字节空间。__heap_base堆的起始地址,__heap_limit堆的结束地址。堆由低向高生长。动态分配内存用到堆。 PRESERVE8 -- 指定当前文件的堆/栈按照8 字节对齐。 THUMB-- 表示后面指令兼容THUMB 指令。THUBM 是ARM 以前的指令集,16bit;现在Cortex-M 系列的都使用THUMB-2 指令集,THUMB-2 是32 位的,兼容16 位和32 位的指令,是THUMB 的超级。 3.向量表 AREA RESET, DATA, READONLY EXPORT __Vectors E XPORT __Vectors_End E XPORT __Vectors_Size 定义一个名为RESET,可读的数据段。并声明__Vectors、__Vectors_End 和__Vectors_Size 这三个标号可被外部的文件使用。 __Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler

STM32库函数功能详解

STM32库函数简介 一、通用输入/输出(GPIO)--------------------------------------------------------------------------------------------3 二、外部中断/事件控制器(EXTI)-----------------------------------------------------------------------------------7 三、通用定时器(TIM)-------------------------------------------------------------------------------------------------9 四:ADC寄存器------------------------------------------------------------------------25 五:备份寄存器(BKP)-------------------------------------------------------------------------------------------------33 六、DMA控制器(DMA)---------------------------------------------------------------37 七、复位和时钟设置(RCC)------------------------------------------------------------------------------------------41 八、嵌套向量中断控制器(NVIC)-----------------------------------------------------------------------------------49

STM32固件库详解

STM32固件库详解基于标准外设库的软件开发 STM32标准外设库概述 STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。该函数库还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了一个中间API,通过使用固件函数库,无需深入掌握底层硬件细节,开发者就可以轻松应用每一个外设。因此,使用固态函数库可以大大减少用户的程序编写时间,进而降低开发成本。每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。每个器件的开发都由一个通用API (application programming interface 应用编程界面)驱动,API对该驱动程序的结构,函数和参数名称都进行了标准化。 ST公司2007年10月发布了版本的固件库,MDK 之前的版本均支持该库。2008年6月发布了版的固件库,从2008年9月推出的MDK 版本至今均使用版本的固件库。以后的版本相对之前的版本改动较大,本书使用目前较新的版本。 使用标准外设库开发的优势 简单的说,使用标准外设库进行开发最大的优势就在于可以使开发者不用深入了解底层硬件细节就可以灵活规范的使用每一个外设。标准外设库覆盖了从GPIO到定时器,再到CAN、I2C、SPI、UART和ADC等等的所有标准外设。对应的C源代码只是用了最基本的C编程的知识,所有代码经过严格测试,易于理解和使用,并且配有完整的文档,非常方便进行二次开发和应用。 STM32F10XXX标准外设库结构与文件描述 1. 标准外设库的文件结构 在上一小节中已经介绍了使用标准外设库的开发的优势,因此对标准外设库的熟悉程度直接影响到程序的编写,下面让我们来认识一下STM32F10XXX的标准外设库。STM32F10XXX的标准外设库经历众多的更新目前已经更新到最新的版本,开发环境中自带的标准外设库为版本,本书中以比较稳定而且较新的版本为基础介绍标准外设库的结构。

STM32固件库使用手册的中文翻译

UM0427用户手册 32位基于ARM微控制器STM32F101xx与STM32F103xx 固件函数库介绍 本手册介绍了32位基于ARM微控制器STM32F101xx与STM32F103xx的固件函数库。 该函数库是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。该函数库还包括每一个外设的驱动描述和应用实例。通过使用本固件函数库,无需深入掌握细节,用户也可以轻松应用每一个外设。因此,使用本固态函数库可以大大减少用户的程序编写时间,进而降低开发成本。 每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。每个器件的开发都由一个通用API (application programming interface 应用编程界面)驱动,API对该驱动程序的结构,函数和参数名称都进行了标准化。 所有的驱动源代码都符合“Strict ANSI-C”标准(项目于范例文件符合扩充ANSI-C标准)。我们已经把驱动源代码文档化,他们同时兼容MISRA-C 2004标准(根据需要,我们可以提供兼容矩阵)。由于整个固态函数库按照“Strict ANSI-C”标准编写,它不受不同开发环境的影响。仅对话启动文件取决于开发环境。 该固态函数库通过校验所有库函数的输入值来实现实时错误检测。该动态校验提高了软件的鲁棒性。实时检测适合于用户应用程序的开发和调试。但这会增加了成本,可以在最终应用程序代码中移去,以优化代码大小和执行速度。想要了解更多细节,请参阅Section 2.5。 因为该固件库是通用的,并且包括了所有外设的功能,所以应用程序代码的大小和执行速度可能不是最优的。对大多数应用程序来说,用户可以直接使用之,对于那些在代码大小和执行速度方面有严格要求的应用程序,该固件库驱动程序可以作为如何设置外设的一份参考资料,根据实际需求对其进行调整。 此份固件库用户手册的整体架构如下: ?定义,文档约定和固态函数库规则。 ?固态函数库概述(包的内容,库的架构),安装指南,库使用实例。 ?固件库具体描述:设置架构和每个外设的函数。 STM32F101xx和STM32F103xx在整个文档中被写作STM32F101x。

STM32函数库的调用

STM32函数库的调用 一·时钟配置.c void RCC_Configuration(void) { /*将外设RCC寄存器重设为缺省值*/ RCC_DeInit(); /*设置外部高速晶振(HSE)*/ RCC_HSEConfig(RCC_HSE_ON); //RCC_HSE_ON——HSE晶振打开(ON) /*等待HSE起振*/ HSEStartUpStatus = RCC_WaitForHSEStartUp(); if(HSEStartUpStatus == SUCCESS) //SUCCESS:HSE晶振稳定且就绪 { /*设置AHB时钟(HCLK)*/ RCC_HCLKConfig(RCC_SYSCLK_Div1); //RCC_SYSCLK_Div1——AHB时钟= 系统时钟 /* 设置高速AHB时钟(PCLK2)*/ RCC_PCLK2Config(RCC_HCLK_Div1); //RCC_HCLK_Div1——APB2时钟= HCLK /*设置低速AHB时钟(PCLK1)*/ RCC_PCLK1Config(RCC_HCLK_Div2); //RCC_HCLK_Div2——APB1时钟= HCLK / 2 /*设置FLASH存储器延时时钟周期数*/ FLASH_SetLatency(FLASH_Latency_2); //FLASH_Latency_2??2延时周期 /*选择FLASH预取指缓存的模式*/ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); // 预取指缓存使能/*设置PLL时钟源及倍频系数*/ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // PLL的输入时钟= HSE时钟频率;RCC_PLLMul_9——PLL输入时钟x 9 /*使能PLL */ RCC_PLLCmd(ENABLE); /*检查指定的RCC标志位(PLL准备好标志)设置与否*/ while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { } /*设置系统时钟(SYSCLK)*/ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//RCC_SYSCLKSource_PLLCLK ——选择PLL作为系统时钟 /* PLL返回用作系统时钟的时钟源*/ while(RCC_GetSYSCLKSource() != 0x08) //0x08:PLL作为系统时钟 {

STM32单片机ADC库函数的定义和使用方法

STM32单片机ADC库函数的定义和使用方法 ADC的基本概念希望各位网友查阅相应的手册,上面对ADC有比较详尽的介绍,包括误差的分析和消除。这里主要介绍ADC的基本库函数的定义和使用。 1.ADC_DeInit函数的功能是将外设ADCx的全部寄存器重设为默认值。 ADC_DeInit(ADC2); 2.ADC_Init函数的功能是根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器。其中ADC_InitTypeDef定义在stm32f10x_adc.h中。其结构体如下所示: typedef struct { u32 ADC_Mode;//可以设置ADC_Mode FunctionalState ADC_ScanConvMode;//规定了模数转换工作在扫描模式还是单次模式,参数可以是ENABLE和DISENABLE FuncTIonalState ADC_CinTInuousConvMode;//规定了模数转换工作在连续还是单次模式,参数可以是ENABLE和DISENABLE u32 ADC_ExternalTrigConv;//定义了使用外部触发来启动规则通道的模数转换 u32 ADC_DataAlign;//规定了ADC数据向左边对齐还是右边对齐参数可以是right和left u8 ADC_NbrOfChannel;//规定了顺序进行规则转换的ADC通道的数目。参数可以是1~16 }ADC_InitTypeDef 例:初始化ADC1(可以按照自己的需要来初始化,这里只是一个例) ADC_InitTypeDef ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_CinTInuousConvMode = DISENABLE; ADC_InitStructure.ADC_ExternalTrigconv = ADC_ExternalTrigconv_T1_CC1; ADC_InitStructure.ADC_Data_Align = ADC_DataAlign_RIGHT; ADC_InitStructure.ADC_NbrOfChannel = 16;

stm32DAC函数库详解

DAC固件库函数 DAC固件库函数 函数名描述 void DAC_DeInit(void) DAC外围寄存器默认复位值。VoidDAC_Init(uint32_tDAC_Channel,DAC_InitTypeDef* DAC_InitStruct) 根据外围初始化指定的DAC void DAC_StructInit(DAC_InitTypeDef* DAC_InitStruct) 把DAC_StructInit 中的每一个参 数按缺省值填入 voidDAC_Cmd(uint32_t DAC_Channel, FunctionalState NewState) 使能或使能指定的DAC通道。 void DAC_ITConfig(uint32_t DAC_Channel, uint32_t DAC_IT, FunctionalState NewState) 使能或者失能指定的DAC 的中断 voidDAC_DMACmd(uint32_tDAC_Channel,FunctionalState NewState) 使能或者失能指定的DAC通道DMA请求。 void DAC_SoftwareTriggerCmd(uint32_t DAC_Channel, FunctionalState NewState) 使能或者失能用选定的DAC通道软件触发 voidDAC_DualSoftwareTriggerCmd(FunctionalState NewState) 使能或者使能双软件触发命令 void DAC_WaveGenerationCmd(uint32_t DAC_Channel, uint32_t DAC_Wave, FunctionalState NewState) 使能或者使能选定的DAC通道波的产生。 void DAC_SetChannel1Data(uint32_t DAC_Align, uint16_t Data) 设置通道1 的数据 void DAC_SetChannel2Data(uint32_t DAC_Align, uint16_t Data) 设置通道2 的数据 void DAC_SetDualChannelData(uint32_t DAC_Align, uint16_t Data2, uint16_t Data1) 设置双通道的数据 uint16_tDAC_GetDataOutputValue(uint32_t DAC_Channel) 返回选定DAC通道最后的数据输出值。 FlagStatus DAC_GetFlagStatus(uint32_t DAC_Channel, uint32_t DAC_FLAG) 检查指定的DAC标志位设置与否。 void DAC_ClearFlag(uint32_t DAC_Channel, uint32_t DAC_FLAG) 清除指定的DAC标志位。 ITStatus DAC_GetITStatus(uint32_t DAC_Channel, uint32_t DAC_IT) 检查指定的DAC 中断是否发生 void DAC_ClearITPendingBit(uint32_t DAC_Channel, uint32_t DAC_IT) 清除DACx 的中断待处理位

移植stm32函数库笔记

USE_STDPERIPH_DRIVER, STM32F10X_HD compiling stm32f10x_usart.c... .\CMSIS\stm32f10x.h(96): error: #35: #error directive: "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)" .\CMSIS\stm32f10x.h: #error "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)" .\CMSIS\stm32f10x.h: ^ .\CMSIS\stm32f10x.h: FWlib\src\stm32f10x_usart.c: 0 warnings, 1 error compiling stm32f10x_wwdg.c... .\CMSIS\stm32f10x.h(96): error: #35: #error directive: "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)" .\CMSIS\stm32f10x.h: #error "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)" .\CMSIS\stm32f10x.h: ^ .\CMSIS\stm32f10x.h: FWlib\src\stm32f10x_wwdg.c: 0 warnings, 1 error compiling SetClock.c... .\CMSIS\stm32f10x.h(96): error: #35: #error directive: "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)" .\CMSIS\stm32f10x.h: #error "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)" .\CMSIS\stm32f10x.h: ^ 在这里添加USE_STDPERIPH_DRIVER, STM32F10X_HD 问题解决

STM32库函数说明及示例

STM32库函数说明及示例(版本V1.4.0) ----第一篇:GPIO库 相关术语说明: gpio:通用输入输出接口 gpio管脚:一个io管脚,这个管脚可以有多个配置。在库函数中用GPIO_Pin_1这样的宏定义表示 gpio端口(gpio分组):一组gpio管脚的信息。在库函数中用宏定义GPIOA GPIOB等表示 1 gpio库说明 库文件名:stm32f4xx_gpio.c 文档提示翻译: 如何使用这个驱动 (1)使用RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOx, ENABLE)函数使能GPIO的AHB总线时钟。 (2)使用GPIO_Init()函数对每个引脚进行四种可能的配置 《1》输入状态:Floating(浮空), Pull-up(上拉), Pull-down(下拉) 《2》输出状态:Push-Pull (上拉下拉)(Pull-up(上拉), Pull-down(下拉)or no Pull(不上拉也不下拉)),Open Drain(开漏)(Pull-up(上拉), Pull-down(下拉)or no Pull(不上拉也不下拉)),在输出模式,速度配置成2MHZ,25MHZ,50MHZ和100MHZ. 《3》第二功能:上拉下拉和开漏 《4》模拟:当一个管脚被用作ADC通道或者DAC输出的时候,需要配置成此模式(3)外设的第二功能: 《1》在ADC和DAC模式,使用GPIO_InitStruct->GPIO_Mode = GPIO_Mode_AN 把需要的管脚配置成模拟模式 《2》对于其它的管脚(定时器,串口等): l 使用GPIO_PinAFConfig()函数把管脚和需要的第二功能进行连接 l 使用GPIO_InitStruct->GPIO_Mode = GPIO_Mode_AF把需要的管脚配置成第二功能模式l 通过成员变量GPIO_PuPd, GPIO_OType and GPIO_Speed选择类型,上拉下拉和输出速度 l 调用函数GPIO_Init() (4)在输入模式,使用函数GPIO_ReadInputDataBit()得到配置好管脚的电平 (5)在输出模式,使用函数GPIO_SetBits()/GPIO_ResetBits()设置配置好IO的高低电平 (6)在复位过程和刚刚复位后,第二功能是无效的,GPIO被配置成了输入浮空模式(JTAG管脚除外) (7)当LSE振荡器关闭的时候,LSE振荡器管脚OSC32_IN和OSC32_OUT可以作为通过IO来使用(分别用PC14和PC15表示)。LSE的优先级高于GPIO函数 (8)当HSE振荡器关闭的时候,HSE振荡器管脚OSC_IN和OSC_OUT可以作为通用IO(PH0,PH1)来使用。HSE的优先级高于GPIO函数。 2 具体函数说明

相关主题