当前位置: 首页 > news >正文

无锡网站策划郑州企业网站模板建站

无锡网站策划,郑州企业网站模板建站,北京装饰公司排名,设计购物网站咋做文章目录#xff1a; 一#xff1a;LED与按键驱动程序 main.c 1.闪灯 led.h led.c 2.按键控制LED亮灭 key.h key.c 二#xff1a;蜂鸣器与继电器驱动程序 main.c 1.蜂鸣器 buzzer.h buzzer.c delay.h delay.c 2.继电器 relay.h relay.c 三#xff1…文章目录 一LED与按键驱动程序 main.c 1.闪灯  led.h led.c  2.按键控制LED亮灭  key.h  key.c 二蜂鸣器与继电器驱动程序 main.c 1.蜂鸣器 buzzer.h buzzer.c delay.h delay.c 2.继电器 relay.h relay.c 三USART串口收发测试程序(超级终端) main.c retarget.h retarget.c usart.h usart.c 四ADC与DMA驱动程序 1.ADC读取电位器与光敏电阻测试程序通过DMA驱动函数的方式用时长  main.c adc.h adc.c 2.DMA  2.1 用DMA读取单路ADC测试程序  main.c 2.2 用DMA读取多路ADC测试程序 main.c 五RTC与BKP驱动程序 1.HAL库自带的RTC时钟测试程序 main.c 2.创建走时完善的RTC时钟测试程序 main.c rtc.h rtc.c 六温湿度传感器DHT11芯片驱动程序 dht11.h dht11.c main.c 七SPI总线闪存芯片驱动程序 w25qxx.h w25qxx.c main.c 八USB从设备串口驱动程序 usbd_cdc_if.h usbd_cdc_if.c main.c 九省电模式、CRC与芯片ID 1.省电模式睡眠、停机、待机  1.1 睡眠模式测试程序 1.2 停机模式测试程序 1.3 待机模式测试程序 2.CRC数据校验方式与芯片ID测试程序 十外部中断与定时器 1.外部中断外部中断的按键测试程序 stm32f1xx_it.c main.c key.c 2.定时器 2.1 定时器中断的闪灯测试程序 2.2 定时器中断的PWM调光测试程序 十一RS485总线有线通讯驱动程序 rs485.h rs485.c usart.c main.c 十二CAN总线有线通讯驱动程序 can1.h can1.c main.c 文件夹结构 Core 存放着内核代码Inc:用于存敝各功能的h库文件Srcmain.c:用于存敝各功能的c文件Starup用于存放汇编语言的单片机启动文件Debug 存放着与仿真器调试相关的文件,里面有“.hex”文件Drivers 存放着HAL库和相关的驱动程序文件CMSIS软件接口标准化文件内核与硬件之间的底层协议DeviceSTM32F1单片机的底层库文件IncludeARM内核与STM32F1单片机硬件之间的底层协议库文件STM32Fx_DriverHAL库文件HAL库各功能的h文件HAL库各功能的c文件icode 存放用户自建的板级硬件驱动程序Middlewares 存放着与“中间件”相关的驱动程序文件USB_DEVICE 存放着USB从设备的驱动程序文件.project CubeIDE工程的启动文件.ioc CubeMX图形界面的启动文件  创建驱动程序文件  1.创建驱动程序总文件夹鼠标右键点击工程名——点击新建——点击Source Floder源文件夹——文件夹名称A“icode”——点击完成2.创建驱动程序文件夹 点击(A)icode文件夹鼠标右键——点击新建——点击文件夹——文件夹命名B——点击完成2.1 创建.c源文件 点击B文件夹鼠标右键——点击新建——点击Source File源文件——文件夹命名C.c——点击完成2.2 创建.h头文件 点击B文件夹鼠标右键——点击新建——点击Header File头文件——文件夹命名C.h——点击完成 一LED与按键驱动程序 main.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.hint main(void) {if(KEY_1()) //按键KEY1判断为1时按键按下{LED_1(1);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭}if(KEY_2()) //按键KEY2判断为1时按键按下{LED_1(0);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭}} 1.闪灯  led文件夹   led.h #ifndef LED_LED_H_ #define LED_LED_H_#include stm32f1xx_hal.h //HAL库文件声明 #include main.h //IO定义与初始化函数在main.c文件中必须引用void LED_1(uint8_t a);//LED1独立控制函数0为熄灭其他值为点亮 void LED_2(uint8_t a);//LED2独立控制函数0为熄灭其他值为点亮 void LED_ALL(uint8_t a);//LED1~4整组操作函数低4位的1/0状态对应4个LED亮灭最低位对应LED1 void LED_1_Contrary(void);//LED1状态取反 void LED_2_Contrary(void);//LED2状态取反#endif /* LED_LED_H_ */ led.c  #include led.hvoid LED_1(uint8_t a)//LED1独立控制函数0为熄灭其他值为点亮 {if(a)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET); }void LED_2(uint8_t a)//LED2独立控制函数0为熄灭其他值为点亮 {if(a)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET); }void LED_ALL(uint8_t a)//LED1~2整组操作函数低2位的1/0状态对应2个LED亮灭最低位对应LED1 {if(a0x01)HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_SET);else HAL_GPIO_WritePin(GPIOB,LED1_Pin,GPIO_PIN_RESET);if(a0x02)HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_SET);else HAL_GPIO_WritePin(GPIOB,LED2_Pin,GPIO_PIN_RESET); }void LED_1_Contrary(void){HAL_GPIO_WritePin(GPIOB,LED1_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED1_Pin)); }void LED_2_Contrary(void){HAL_GPIO_WritePin(GPIOB,LED2_Pin,1-HAL_GPIO_ReadPin(GPIOB,LED2_Pin)); } 2.按键控制LED亮灭  key文件夹  key.h  #ifndef KEY_KEY_H_ #define KEY_KEY_H_#include stm32f1xx_hal.h //HAL库文件声明 #include main.h //IO定义与初始化函数在main.c文件中必须引用uint8_t KEY_1(void);//按键1 uint8_t KEY_2(void);//按键2#endif /* KEY_KEY_H_ */ key.c #include key.huint8_t KEY_1(void) {uint8_t a;a0;//如果未进入按键处理则返回0if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)GPIO_PIN_RESET){//读按键接口的电平HAL_Delay(20);//延时去抖动if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)GPIO_PIN_RESET){ //读按键接口的电平a1;//进入按键处理返回1}}while(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)GPIO_PIN_RESET); //等待按键松开return a; }uint8_t KEY_2(void) {uint8_t a;a0;//如果未进入按键处理则返回0if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)GPIO_PIN_RESET){//读按键接口的电平HAL_Delay(20);//延时去抖动if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)GPIO_PIN_RESET){ //读按键接口的电平a1;//进入按键处理返回1}}while(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)GPIO_PIN_RESET); //等待按键松开return a; } 二蜂鸣器与继电器驱动程序 main.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.h#include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h#include ../../icode/relay/relay.hint main(void) {if(KEY_1()) //按键KEY1判断为1时按键按下{LED_1(1);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数RELAY_1(1);//继电器的控制程序c0继电器放开c1继电器吸合}if(KEY_2()) //按键KEY2判断为1时按键按下{LED_1(0);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭BUZZER_SOLO2();//蜂鸣器输出单音的报警音样式2CPU微秒级延时RELAY_1(0);//继电器的控制程序c0继电器放开c1继电器吸合}} 1.蜂鸣器 buzzer文件夹  PB5 n/a High output Push Pull High BEEP1 buzzer.h #ifndef BUZZER_BUZZER_H_ #define BUZZER_BUZZER_H_#include stm32f1xx_hal.h //HAL库文件声明 #include main.h #include ../delay/delay.h void BUZZER_SOLO1(void); void BUZZER_SOLO2(void);#endif /* BUZZER_BUZZER_H_ */ buzzer.c #include buzzer.h#define time1 50 //单音的时长 #define hz1 1 //单音的音调单位毫秒void BUZZER_SOLO1(void){//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数uint16_t i;for(i0;itime1;i){//循环次数决定单音的时长HAL_GPIO_WritePin(BEEP1_GPIO_Port,BEEP1_Pin,GPIO_PIN_RESET); //蜂鸣器接口输出低电平0HAL_Delay(hz1); //延时毫秒级延时最小1微秒实现的单调较低因不需要额外编写微秒级延时函数所以最简单实用HAL_GPIO_WritePin(BEEP1_GPIO_Port,BEEP1_Pin,GPIO_PIN_SET); //蜂鸣器接口输出高电平1HAL_Delay(hz1); //延时} } #define time2 200 //单音的时长 #define hz2 500 //单音的音调单位微秒 void BUZZER_SOLO2(void){//蜂鸣器输出单音的报警音样式2CPU微秒级延时uint16_t i;for(i0;itime2;i){//循环次数决定单音的时长HAL_GPIO_WritePin(BEEP1_GPIO_Port,BEEP1_Pin,GPIO_PIN_RESET); //蜂鸣器接口输出低电平0delay_us(hz2); //延时HAL_GPIO_WritePin(BEEP1_GPIO_Port,BEEP1_Pin,GPIO_PIN_SET); //蜂鸣器接口输出高电平1delay_us(hz2); //延时} } delay文件夹  delay.h #ifndef DELAY_DELAY_H_ #define DELAY_DELAY_H_#include stm32f1xx_hal.h //HAL库文件声明 void delay_us(uint32_t us); //C文件中的函数声明#endif /* DELAY_DELAY_H_ */ delay.c #include delay.hvoid delay_us(uint32_t us) //利用CPU循环实现的非精准应用的微秒延时函数 {uint32_t delay (HAL_RCC_GetHCLKFreq() / 8000000 * us); //使用HAL_RCC_GetHCLKFreq()函数获取主频值经算法得到1微秒的循环次数while (delay--); //循环delay次达到1微秒延时 } 2.继电器 relay文件夹  relay.h #ifndef INC_RELAY_H_ #define INC_RELAY_H_//继电器接口定义与初始化函数在MX中设置并生成在main.c文件中 #include stm32f1xx_hal.h //HAL库文件声明 #include main.h //IO定义与初始化函数在main.c文件中必须引用void RELAY_1(uint8_t c);//继电器控制1#endif /* INC_RELAY_H_ */ relay.c #include relay.hvoid RELAY_1(uint8_t c){ //继电器的控制程序c0继电器放开c1继电器吸合if(c)HAL_GPIO_WritePin(GPIOA,RELAY1_Pin,GPIO_PIN_RESET); //继电器吸else HAL_GPIO_WritePin(GPIOA,RELAY1_Pin,GPIO_PIN_SET); //继电器松 } 三USART串口收发测试程序(超级终端) syscalls.c文件与添加的内容冲突发送信号所有先禁止此文件参与编译后再加入我们新的文件  Core文件夹——Src文件夹——syscalls.c文件——鼠标右击属性——左侧点击C/C Build——右侧勾选Exclude resource from build——应用并关闭 接收信号  开启USART1串口接收中断打开CubeMX图形界面——Connectivity——USART1——NMC Settings——勾选USART1 global interruptmain.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.h #include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h #include ../../icode/relay/relay.h#include ../inc/retarget.h //用于printf函数串口重映射 #include ../../icode/usart/usart.h //串口接收RetargetInit(huart1); //将printf()函数映射到UART1串口上 HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1); //开启串口1接收中断MX_ADC1_Init(); MX_ADC2_Init();while (1){if(KEY_1()) //按键KEY1判断为1时按键按下{LED_1(1);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数RELAY_1(1);//继电器的控制程序c0继电器放开c1继电器吸合HAL_UART_Transmit(huart1,(uint8_t*)KEY1\r\n,6,0xffff);//串口发送串口号1内容ABC数量3溢出时间0xffff}if(KEY_2()) //按键KEY2判断为1时按键按下{LED_1(0);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭BUZZER_SOLO2();//蜂鸣器输出单音的报警音样式2CPU微秒级延时RELAY_1(0);//继电器的控制程序c0继电器放开c1继电器吸合printf(KEY2\r\n);//向USART1串口发送字符串}//键盘输入“1回车”或“O回车” 键盘输入“1”或“0”if(USART1_RX_STA 0xc000){//串口1判断中断接收标志位 USART1_RX_STA0x0001if(USART1_RX_BUF[0]1){LED_1(1);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数RELAY_1(1);//继电器的控制程序c0继电器放开c1继电器吸合}if(USART1_RX_BUF[0]0){LED_1(0);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭BUZZER_SOLO2();//蜂鸣器输出单音的报警音样式2CPU微秒级延时RELAY_1(0);//继电器的控制程序c0继电器放开c1继电器吸合}USART1_RX_STA0;//串口接收标志清0即开启下一轮接收}} ...\Core\Src下新建 retarget.c文件 ...\Core\Inc下新建 retarget.h文件 retarget.h #ifndef INC_RETARGET_H_ #define INC_RETARGET_H_#include stm32f1xx_hal.h #include stdio.h//用于printf函数串口重映射 #include sys/stat.hvoid RetargetInit(UART_HandleTypeDef *huart);int _isatty(int fd); int _write(int fd, char* ptr, int len); int _close(int fd); int _lseek(int fd, int ptr, int dir); int _read(int fd, char* ptr, int len); int _fstat(int fd, struct stat* st);#endif /* INC_RETARGET_H_ */ retarget.c #include _ansi.h #include _syslist.h #include errno.h #include sys/time.h #include sys/times.h #include limits.h #include signal.h #include ../Inc/retarget.h #include stdint.h #include stdio.h #if !defined(OS_USE_SEMIHOSTING) #define STDIN_FILENO 0 #define STDOUT_FILENO 1 #define STDERR_FILENO 2UART_HandleTypeDef *gHuart;void RetargetInit(UART_HandleTypeDef *huart) {gHuart huart;/* Disable I/O buffering for STDOUT stream, so that* chars are sent out as soon as they are printed. */setvbuf(stdout, NULL, _IONBF, 0); } int _isatty(int fd) {if (fd STDIN_FILENO fd STDERR_FILENO)return 1;errno EBADF;return 0; } int _write(int fd, char* ptr, int len) {HAL_StatusTypeDef hstatus;if (fd STDOUT_FILENO || fd STDERR_FILENO) {hstatus HAL_UART_Transmit(gHuart, (uint8_t *) ptr, len, HAL_MAX_DELAY);if (hstatus HAL_OK)return len;elsereturn EIO;}errno EBADF;return -1; } int _close(int fd) {if (fd STDIN_FILENO fd STDERR_FILENO)return 0;errno EBADF;return -1; } int _lseek(int fd, int ptr, int dir) {(void) fd;(void) ptr;(void) dir;errno EBADF;return -1; } int _read(int fd, char* ptr, int len) {HAL_StatusTypeDef hstatus;if (fd STDIN_FILENO) {hstatus HAL_UART_Receive(gHuart, (uint8_t *) ptr, 1, HAL_MAX_DELAY);if (hstatus HAL_OK)return 1;elsereturn EIO;}errno EBADF;return -1; } int _fstat(int fd, struct stat* st) {if (fd STDIN_FILENO fd STDERR_FILENO) {st-st_mode S_IFCHR;return 0;}errno EBADF;return 0; }#endif //#if !defined(OS_USE_SEMIHOSTING) usart文件夹 usart.h #ifndef INC_USART_H_ #define INC_USART_H_#include stm32f1xx_hal.h //HAL库文件声明 #include string.h//用于字符串处理的库 #include ../inc/retarget.h//用于printf函数串口重映射extern UART_HandleTypeDef huart1;//声明USART1的HAL库结构体 extern UART_HandleTypeDef huart2;//声明USART2的HAL库结构体 extern UART_HandleTypeDef huart3;//声明USART2的HAL库结构体#define USART1_REC_LEN 200//定义USART1最大接收字节数 #define USART2_REC_LEN 200//定义USART1最大接收字节数 #define USART3_REC_LEN 200//定义USART1最大接收字节数extern uint8_t USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 extern uint16_t USART1_RX_STA;//接收状态标记 extern uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存extern uint8_t USART2_RX_BUF[USART2_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 extern uint16_t USART2_RX_STA;//接收状态标记 extern uint8_t USART2_NewData;//当前串口中断接收的1个字节数据的缓存 extern uint8_t RS485orBT;//当RS485orBT标志位为1时是RS485模式为0时是蓝牙模式extern uint8_t USART3_RX_BUF[USART3_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 extern uint16_t USART3_RX_STA;//接收状态标记 extern uint8_t USART3_NewData;//当前串口中断接收的1个字节数据的缓存void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);//串口中断回调函数声明#endif /* INC_USART_H_ */ usart.c #include usart.huint8_t USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节. uint16_t USART1_RX_STA0;//接收状态标记//bit15接收完成标志bit14接收到0x0dbit13~0接收到的有效字节数目 uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存uint8_t USART2_RX_BUF[USART2_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节. uint16_t USART2_RX_STA0;//接收状态标记//bit15接收完成标志bit14接收到0x0dbit13~0接收到的有效字节数目 uint8_t USART2_NewData;//当前串口中断接收的1个字节数据的缓存 uint8_t RS485orBT;//当RS485orBT标志位为1时是RS485模式为0时是蓝牙模式uint8_t USART3_RX_BUF[USART3_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节. uint16_t USART3_RX_STA0;//接收状态标记//bit15接收完成标志bit14接收到0x0dbit13~0接收到的有效字节数目 uint8_t USART3_NewData;//当前串口中断接收的1个字节数据的缓存void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//串口中断回调函数 {if(huart huart1)//判断中断来源串口1USB转串口{printf(%c,USART1_NewData); //把收到的数据以 a符号变量 发送回电脑if((USART1_RX_STA0x8000)0){//接收未完成if(USART1_RX_STA0x4000){//接收到了0x0dif(USART1_NewData!0x0a)USART1_RX_STA0;//接收错误,重新开始else USART1_RX_STA|0x8000; //接收完成了}else{ //还没收到0X0Dif(USART1_NewData0x0d)USART1_RX_STA|0x4000;else{USART1_RX_BUF[USART1_RX_STA0X3FFF]USART1_NewData; //将收到的数据放入数组USART1_RX_STA; //数据长度计数加1if(USART1_RX_STA(USART1_REC_LEN-1))USART1_RX_STA0;//接收数据错误,重新开始接收}}}HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1); //再开启接收中断}if(huart huart2)//判断中断来源RS485/蓝牙模块{if(RS485orBT){//当RS485orBT标志位为1时是RS485模式为0时是蓝牙模式USART2_RX_BUF[0]USART2_NewData;//将接收到的数据放入缓存数组因只用到1个数据所以只存放在数据[0]位置USART2_RX_STA;//数据接收标志位加1}else{printf(%c,USART2_NewData); //把收到的数据以 a符号变量 发送回电脑}HAL_UART_Receive_IT(huart2,(uint8_t *)USART2_NewData, 1); //再开启接收中断}if(huart huart3)//判断中断来源串口3WIFI模块{printf(%c,USART3_NewData); //把收到的数据以 a符号变量 发送回电脑HAL_UART_Receive_IT(huart3,(uint8_t *)USART3_NewData,1); //再开启接收中断} } 四ADC与DMA驱动程序 1.ADC读取电位器与光敏电阻测试程序通过DMA驱动函数的方式用时长  逻辑电平输入只能读到高、低电平1或0ADC输入可读出区间内(0~3.3v)的电压值设置  CubeMX的设置——时钟配置窗口——可设置ADC时钟的分频系数ADC Prescaler为8——设置ADC时钟最终频率To ADC1,2为9端口视图的设置——PA4端口的模式设置为ADC1_IN4——PA5端口的模式设置为ADC2_IN5Analog功能组中——ADC1功能——确定IN4是否被自动勾选——ADC2功能——确定IN5是否被自动勾选在参数选项卡中——将Rank第1组中的转换时间设置为55.5个时钟周期 main.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.h #include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h #include ../../icode/relay/relay.h #include ../inc/retarget.h//用于printf函数串口重映射 #include ../../icode/usart/usart.h#include ../../icode/adc/adc.hint main(void) {uint16_t a1,a2;//用于ADC数据读取的暂时变量RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断//在ADC开始转换之前先校转换电路使得后续转换得出的值更精确HAL_ADCEx_Calibration_Start(hadc1);//ADC采样校准if(KEY_1()) //按键KEY1判断为1时按键按下{LED_1(1);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数RELAY_1(1);//继电器的控制程序c0继电器放开c1继电器吸合HAL_UART_Transmit(huart1,(uint8_t*)KEY1\r\n,6,0xffff);//串口发送串口号1内容ABC数量3溢出时间0xffff}if(KEY_2()) //按键KEY2判断为1时按键按下{LED_1(0);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭BUZZER_SOLO2();//蜂鸣器输出单音的报警音样式2CPU微秒级延时RELAY_1(0);//继电器的控制程序c0继电器放开c1继电器吸合printf(KEY2\r\n);//向USART1串口发送字符串}if(USART1_RX_STA0x0001){//串口1判断中断接收标志位if(USART1_RX_BUF[0]1){LED_1(1);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数RELAY_1(1);//继电器的控制程序c0继电器放开c1继电器吸合}if(USART1_RX_BUF[0]0){LED_1(0);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭BUZZER_SOLO2();//蜂鸣器输出单音的报警音样式2CPU微秒级延时RELAY_1(0);//继电器的控制程序c0继电器放开c1继电器吸合}USART1_RX_STA0;//串口接收标志清0即开启下一轮接收}a1 ADC_IN_1();//读出ADC1数值电位器a2 ADC_IN_2();//读出ADC2数值光敏电阻//强制以4位输出printf(ADC1%04d ADC2%04d \r\n,a1,a2);//向USART1串口发送字符串HAL_Delay(500);//在主循环里写入HAL库的毫秒级延时函数 } adc文件夹 adc.h #ifndef ADC_ADC_H_ #define ADC_ADC_H_#include stm32f1xx_hal.h //HAL库文件声明 extern ADC_HandleTypeDef hadc1; extern ADC_HandleTypeDef hadc2;uint16_t ADC_IN_1(void); uint16_t ADC_IN_2(void);#endif /* ADC_ADC_H_ */ adc.c #include adc.huint16_t ADC_IN_1(void) //ADC采集程序 {HAL_ADC_Start(hadc1);//开始ADC采集HAL_ADC_PollForConversion(hadc1,500);//等待采集结束if(HAL_IS_BIT_SET(HAL_ADC_GetState(hadc1), HAL_ADC_STATE_REG_EOC))//读取ADC完成标志位{return HAL_ADC_GetValue(hadc1);//读出ADC数值}return 0; }uint16_t ADC_IN_2(void) //ADC采集程序 {HAL_ADC_Start(hadc2);//开始ADC采集HAL_ADC_PollForConversion(hadc2,500);//等待采集结束if(HAL_IS_BIT_SET(HAL_ADC_GetState(hadc2), HAL_ADC_STATE_REG_EOC))//读取ADC完成标志位{return HAL_ADC_GetValue(hadc2);//读出ADC数值}return 0; } 2.DMA  2.1 用DMA读取单路ADC测试程序  设置 Analog功能组中——ADC1功能1——左下方NMC Settings——勾选DMA1的中断允许——ADC1功能1——DMA Settings——点击Add——选择ADC1——右边设置为Hight——选择循环模式Mode——Circular——勾选Memory寄存器——选择半字数据宽度Half Word在参数选项卡中——Continuous Conmversion Mode——Enabled开启连续转换模式CubeMX的设置——工程管理选项卡Project Manager——点击高级子选项卡Advanced Settings——选择DMA一行——点击列表右上方的排序上移 main.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.h #include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h #include ../../icode/relay/relay.h #include ../inc/retarget.h//用于printf函数串口重映射 #include ../../icode/usart/usart.h #include ../../icode/adc/adc.hvoid SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_RTC_Init(void);static void MX_DMA_Init(void);MX_ADC1_Init(); MX_CAN_Init(); MX_SPI2_Init(); MX_USART1_UART_Init(); MX_USART2_UART_Init(); MX_USART3_UART_Init(); MX_USB_PCD_Init(); MX_ADC2_Init();int main(void) {RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断HAL_ADCEx_Calibration_Start(hadc1);//ADC采样校准HAL_ADC_Start_DMA(hadc1,(uint32_t*)a1,1);//启动DMA。传递的功能传递的数据,传递的数据长度while (1){if(KEY_1()) //按键KEY1判断为1时按键按下{LED_1(1);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数RELAY_1(1);//继电器的控制程序c0继电器放开c1继电器吸合HAL_UART_Transmit(huart1,(uint8_t*)KEY1\r\n,6,0xffff);//串口发送串口号1内容ABC数量3溢出时间0xffff}if(KEY_2()) //按键KEY2判断为1时按键按下{LED_1(0);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭BUZZER_SOLO2();//蜂鸣器输出单音的报警音样式2CPU微秒级延时RELAY_1(0);//继电器的控制程序c0继电器放开c1继电器吸合printf(KEY2\r\n);//向USART1串口发送字符串}if(USART1_RX_STA0x0001){//串口1判断中断接收标志位if(USART1_RX_BUF[0]1){LED_1(1);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数RELAY_1(1);//继电器的控制程序c0继电器放开c1继电器吸合}if(USART1_RX_BUF[0]0){LED_1(0);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭BUZZER_SOLO2();//蜂鸣器输出单音的报警音样式2CPU微秒级延时RELAY_1(0);//继电器的控制程序c0继电器放开c1继电器吸合}USART1_RX_STA0;//串口接收标志清0即开启下一轮接收}//a1 ADC_IN_1();//读出ADC1数值电位器 由于ADC1已经改用DMA读取a2 ADC_IN_2();//读出ADC2数值光敏电阻printf(ADC1%04d ADC2%04d \r\n,a1,a2);//向USART1串口发送字符串HAL_Delay(500);//在主循环里写入HAL库的毫秒级延时函数 } 2.2 用DMA读取多路ADC测试程序 设置 因为ADC2不支持DMA我们只能把ADC2的通道5改成ADC1的通道5然后在ADC1里用DMA循环交替读通道4和通道5的数值在单片机端口初视图中点晶PA5——点击ADC2_IN5取消选择——点击ADC1_IN5——重新选择为ADC1_IN5Analog功能组中——ADC1功能1——Parameter Settings——Number of Conversion——2将通道数里设置为2 ——Rank1——Channel 4——Rank2——Channel 5 main.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.h #include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h #include ../../icode/relay/relay.h #include ../inc/retarget.h//用于printf函数串口重映射 #include ../../icode/usart/usart.h #include ../../icode/adc/adc.hint main(void) {uint16_t dmaadc[2];//用于多路ADC数据读取的暂时数组RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断HAL_ADCEx_Calibration_Start(hadc1);//ADC采样校准HAL_ADC_Start_DMA(hadc1,(uint32_t*)dmaadc,2);//启动DMA,采集数据存入的变量地址,长度while (1){if(KEY_1()) //按键KEY1判断为1时按键按下{LED_1(1);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数RELAY_1(1);//继电器的控制程序c0继电器放开c1继电器吸合HAL_UART_Transmit(huart1,(uint8_t*)KEY1\r\n,6,0xffff);//串口发送串口号1内容ABC数量3溢出时间0xffff}if(KEY_2()) //按键KEY2判断为1时按键按下{LED_1(0);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭BUZZER_SOLO2();//蜂鸣器输出单音的报警音样式2CPU微秒级延时RELAY_1(0);//继电器的控制程序c0继电器放开c1继电器吸合printf(KEY2\r\n);//向USART1串口发送字符串}if(USART1_RX_STA0x0001){//串口1判断中断接收标志位if(USART1_RX_BUF[0]1){LED_1(1);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数RELAY_1(1);//继电器的控制程序c0继电器放开c1继电器吸合}if(USART1_RX_BUF[0]0){LED_1(0);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭BUZZER_SOLO2();//蜂鸣器输出单音的报警音样式2CPU微秒级延时RELAY_1(0);//继电器的控制程序c0继电器放开c1继电器吸合}USART1_RX_STA0;//串口接收标志清0即开启下一轮接收}// a1 ADC_IN_1();//读出ADC1数值电位器 // a2 ADC_IN_2();//读出ADC2数值光敏电阻printf(ADC1%04d ADC2%04d \r\n,dmaadc[0],dmaadc[1]);//向USART1串口发送字符串 通道4和通道5HAL_Delay(500);//在主循环里写入HAL库的毫秒级延时函数 } 五RTC与BKP驱动程序 1.HAL库自带的RTC时钟测试程序 设置 开启RTC功能打开时钟数视图——RTC的时钟这里选择LSE外部低速时钟LSE——频率为32.7⑥8KHzTimers——RTC——勾选Activate Clock Source激活时钟 Activate Calendar激活日历——Parameter Settings——按默认设置 main.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.h #include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h #include ../../icode/relay/relay.h #include ../inc/retarget.h//用于printf函数串口重映射 #include ../../icode/usart/usart.hint main(void) {RTC_DateTypeDef RtcDate;RTC_TimeTypeDef RtcTime;while (1){if(USART1_RX_STA0xC000){ //如果标志位是0xC000表示收到数据串完成可以处理。if((USART1_RX_STA0x3FFF)0){ //单独的回车键再显示一次欢迎词HAL_RTC_GetTime(hrtc, RtcTime, RTC_FORMAT_BIN);//读出时间值HAL_RTC_GetDate(hrtc, RtcDate, RTC_FORMAT_BIN);//一定要先读时间后读日期printf( 洋桃IoT开发板RTC实时时钟测试 \r\n);printf( 实时时间%04d-%02d-%02d %02d:%02d:%02d \r\n,2000RtcDate.Year,RtcDate.Month, RtcDate.Date,RtcTime.Hours, RtcTime.Minutes, RtcTime.Seconds);//显示日期时间printf( 单按回车键更新时间输入字母C初始化时钟 \r\n);printf( 请输入设置时间格式20170806120000按回车键确定 \r\n);}else if((USART1_RX_STA0x3FFF)1){ //判断数据是不是1个if(USART1_RX_BUF[0]c || USART1_RX_BUF[0]C){MX_RTC_Init(); //键盘输入c或C初始化时钟printf(初始化成功 \r\n);//显示初始化成功}else{printf(指令错误 \r\n); //显示指令错误}}else if((USART1_RX_STA0x3FFF)14){ //判断数据是不是14个//将超级终端发过来的数据换算并写入RTCRtcDate.Year (USART1_RX_BUF[2]-0x30)*10USART1_RX_BUF[3]-0x30;//减0x30后才能得到十进制0~9的数据RtcDate.Month (USART1_RX_BUF[4]-0x30)*10USART1_RX_BUF[5]-0x30;RtcDate.Date (USART1_RX_BUF[6]-0x30)*10USART1_RX_BUF[7]-0x30;RtcTime.Hours (USART1_RX_BUF[8]-0x30)*10USART1_RX_BUF[9]-0x30;RtcTime.Minutes (USART1_RX_BUF[10]-0x30)*10USART1_RX_BUF[11]-0x30;RtcTime.Seconds (USART1_RX_BUF[12]-0x30)*10USART1_RX_BUF[13]-0x30;if (HAL_RTC_SetTime(hrtc, RtcTime, RTC_FORMAT_BIN) ! HAL_OK)//将数据写入RTC程序{printf(写入时间失败 \r\n); //显示写入失败}else if (HAL_RTC_SetDate(hrtc, RtcDate, RTC_FORMAT_BIN) ! HAL_OK)//将数据写入RTC程序{printf(写入日期失败 \r\n); //显示写入失败}else printf(写入成功 \r\n);//显示写入成功}else{ //如果以上都不是即是错误的指令。printf(指令错误 \r\n); //如果不是以上正确的操作显示指令错误}USART1_RX_STA0; //将串口数据标志位清0}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}static void MX_RTC_Init(void){RTC_TimeTypeDef sTime {0};RTC_DateTypeDef DateToUpdate {0};__HAL_RCC_PWR_CLK_ENABLE();//使能电源时钟PWRHAL_PWR_EnableBkUpAccess();//取消备份区域写保护hrtc.Instance RTC;hrtc.Init.AsynchPrediv RTC_AUTO_1_SECOND;hrtc.Init.OutPut RTC_OUTPUTSOURCE_ALARM;if (HAL_RTC_Init(hrtc) ! HAL_OK){Error_Handler();}if(HAL_RTCEx_BKUPRead(hrtc,RTC_BKP_DR1)!0X5050)//判断是否首次上电{HAL_RTCEx_BKUPWrite(hrtc,RTC_BKP_DR1,0X5050); //标记数值写入上电检查数值sTime.Hours 0x0;sTime.Minutes 0x0;sTime.Seconds 0x0;if (HAL_RTC_SetTime(hrtc, sTime, RTC_FORMAT_BCD) ! HAL_OK){Error_Handler();}DateToUpdate.WeekDay RTC_WEEKDAY_MONDAY;DateToUpdate.Month RTC_MONTH_JANUARY;DateToUpdate.Date 0x1;DateToUpdate.Year 0x0;if (HAL_RTC_SetDate(hrtc, DateToUpdate, RTC_FORMAT_BCD) ! HAL_OK){Error_Handler();}} 2.创建走时完善的RTC时钟测试程序 BKP寄存器 可以自由存放数据在单片机断电后依然保证RTC特续走时利用备用电池 设置 禁用RTC初始化函数不然初始化会删除正常走时的日期和时阃CubeMX的设置——工程管理选项卡Project Manager——点击高级子选项卡Advanced Settings——选择DTEC一行——勾选Do Not Generate Function Call不生成函数调用——取消勾选Static静态CubeMX的设置——时钟配置窗口——可设置ADC时钟的分频系数ADC Prescaler为8——设置ADC时钟最终频率To ADC1,2为9端口视图的设置——PA4端口的模式设置为ADC1_IN4——PA5端口的模式设置为ADC2_IN5Analog功能组中——ADC1功能——确定IN4是否被自动勾选——ADC2功能——确定IN5是否被自动勾选在参数选项卡中——将Rank第1组中的转换时间设置为55.5个时钟周期 main.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.h #include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h #include ../../icode/relay/relay.h #include ../inc/retarget.h//用于printf函数串口重映射 #include ../../icode/usart/usart.hMX_GPIO_Init();MX_DMA_Init();MX_ADC1_Init();MX_CAN_Init();MX_SPI2_Init();MX_USART1_UART_Init();MX_USART2_UART_Init();MX_USART3_UART_Init();MX_USB_PCD_Init();RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断RTC_Init();//自创走时完善的RTC时钟初始化int main(void) {while (1){if(USART1_RX_STA0xC000){ //如果标志位是0xC000表示收到数据串完成可以处理。if((USART1_RX_STA0x3FFF)0){ //单独的回车键再显示一次欢迎词RTC_Get();//读出当前RTC日期与时间放入全局变量printf( 洋桃IoT开发板RTC实时时钟测试 \r\n);printf( 实时时间%04d-%02d-%02d %02d:%02d:%02d \r\n,ryear, rmon, rday, rhour, rmin, rsec);//显示日期时间printf( 单按回车键更新时间输入字母C初始化时钟 \r\n);printf( 请输入设置时间格式20170806120000按回车键确定 \r\n);}else if((USART1_RX_STA0x3FFF)1){ //判断数据是不是1个if(USART1_RX_BUF[0]c || USART1_RX_BUF[0]C){MX_RTC_Init(); //键盘输入c或C初始化时钟调用HAL库自带的初始化函数printf(初始化成功 \r\n);//显示初始化成功}else{printf(指令错误 \r\n); //显示指令错误}}else if((USART1_RX_STA0x3FFF)14){ //判断数据是不是14个//将超级终端发过来的数据换算并写入RTCryear (USART1_RX_BUF[0]-0x30)*1000 (USART1_RX_BUF[1]-0x30)*100 (USART1_RX_BUF[2]-0x30)*10 (USART1_RX_BUF[3]-0x30);//减0x30得到十进制0~9的数据rmon (USART1_RX_BUF[4]-0x30)*10 (USART1_RX_BUF[5]-0x30);rday (USART1_RX_BUF[6]-0x30)*10 (USART1_RX_BUF[7]-0x30);rhour (USART1_RX_BUF[8]-0x30)*10 (USART1_RX_BUF[9]-0x30);rmin (USART1_RX_BUF[10]-0x30)*10 (USART1_RX_BUF[11]-0x30);rsec (USART1_RX_BUF[12]-0x30)*10 (USART1_RX_BUF[13]-0x30);if (RTC_Set(ryear,rmon,rday,rhour,rmin,rsec) ! HAL_OK)//将数据写入RTC程序{printf(写入时间失败 \r\n); //显示写入失败}else printf(写入成功 \r\n);//显示写入成功}else{ //如果以上都不是即是错误的指令。printf(指令错误 \r\n); //如果不是以上正确的操作显示指令错误}USART1_RX_STA0; //将串口数据标志位清0}void MX_RTC_Init(void){RTC_TimeTypeDef sTime {0};RTC_DateTypeDef DateToUpdate {0};hrtc.Instance RTC;hrtc.Init.AsynchPrediv RTC_AUTO_1_SECOND;hrtc.Init.OutPut RTC_OUTPUTSOURCE_ALARM;if (HAL_RTC_Init(hrtc) ! HAL_OK){Error_Handler();}sTime.Hours 0x0;sTime.Minutes 0x0;sTime.Seconds 0x0;if (HAL_RTC_SetTime(hrtc, sTime, RTC_FORMAT_BCD) ! HAL_OK){Error_Handler();}DateToUpdate.WeekDay RTC_WEEKDAY_MONDAY;DateToUpdate.Month RTC_MONTH_JANUARY;DateToUpdate.Date 0x1;DateToUpdate.Year 0x0;if (HAL_RTC_SetDate(hrtc, DateToUpdate, RTC_FORMAT_BCD) ! HAL_OK){Error_Handler();}} } rtc文件夹 rtc.h #ifndef INC_RTC_H_ #define INC_RTC_H_#include stm32f1xx_hal.h //HAL库文件声明 #include main.h //IO定义与初始化函数在main.c文件中必须引用/* //时间读写与设置说明// 1在mani.c文件中主循环之前放入RTC_Init();可使能RTC时钟。RTC_Init函数自带判断首次上电功能 2使用RTC_Get();读出时间。读出的数据存放在 年 ryear 16位 月 rmon 以下都是8位 日 rday 时 rhour 分 rmin 秒 rsec 周 rweek 3使用RTC_Set(4位年,2位月,2位日,2位时,2位分,2位秒); 写入时间。 例如RTC_Set(2022,8,6,21,34,0);其他函数都是帮助如上3个函数的不需要调用。 注意要使用RTC_Get和RTC_Set的返回值为0时表示读写正确。 */extern RTC_HandleTypeDef hrtc;//声明rtc.c文件中定义的全局变量注意这里不能给变量赋值 extern uint16_t ryear; extern uint8_t rmon,rday,rhour,rmin,rsec,rweek;void RTC_Init(void); //用户自建的带有上电BPK判断的RTC初始化【在主循环前调用】 uint8_t Is_Leap_Year(uint16_t year);//判断是否是闰年函数 uint8_t RTC_Get(void);//读出当前时间值【主函数中需要读RTC时调用】 uint8_t RTC_Set(uint16_t syear,uint8_t smon,uint8_t sday,uint8_t hour,uint8_t min,uint8_t sec);//写入当前时间【主函数中需要写入RTC时调用】 uint8_t RTC_Get_Week(uint16_t year,uint8_t month,uint8_t day);//按年月日计算星期#endif rtc.c #include rtc.h//以下2行全局变量用于RTC时间的读取与读入 uint16_t ryear; //4位年 uint8_t rmon,rday,rhour,rmin,rsec,rweek;//2位月日时分秒周void RTC_Init(void) //用户自建的带有上电BPK判断的RTC初始化 {hrtc.Instance RTC;hrtc.Init.AsynchPrediv RTC_AUTO_1_SECOND;hrtc.Init.OutPut RTC_OUTPUTSOURCE_NONE;if (HAL_RTC_Init(hrtc) ! HAL_OK){Error_Handler();}if(HAL_RTCEx_BKUPRead(hrtc,RTC_BKP_DR1)!0X5050){ //判断是否首次上电HAL_RTCEx_BKUPWrite(hrtc,RTC_BKP_DR1,0X5050); //标记数值 下次不执行“首次上电”的部分RTC_Set(2022,1,1,0,0,0);//写入RTC时间的操作RTC_Set(4位年,2位月,2位日,2位时,2位分,2位秒)} }//判断是否是闰年函数 //月份 1 2 3 4 5 6 7 8 9 10 11 12 //闰年 31 29 31 30 31 30 31 31 30 31 30 31 //非闰年 31 28 31 30 31 30 31 31 30 31 30 31 //输入:年份 //输出:该年份是不是闰年.1,是.0,不是 uint8_t Is_Leap_Year(uint16_t year){if(year%40){ //必须能被4整除if(year%1000){if(year%4000)return 1;//如果以00结尾,还要能被400整除else return 0;}else return 1;}else return 0; } //设置时钟 //把输入的时钟转换为秒钟 //以1970年1月1日为基准 //1970~2099年为合法年份//月份数据表 uint8_t const table_week[12]{0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表 const uint8_t mon_table[12]{31,28,31,30,31,30,31,31,30,31,30,31};//平年的月份日期表//写入时间 uint8_t RTC_Set(uint16_t syear,uint8_t smon,uint8_t sday,uint8_t hour,uint8_t min,uint8_t sec){ //写入当前时间1970~2099年有效uint16_t t;uint32_t seccount0;if(syear2000||syear2099)return 1;//syear范围1970-2099此处设置范围为2000-2099for(t1970;tsyear;t){ //把所有年份的秒钟相加if(Is_Leap_Year(t))seccount31622400;//闰年的秒钟数else seccount31536000; //平年的秒钟数}smon-1;for(t0;tsmon;t){ //把前面月份的秒钟数相加seccount(uint32_t)mon_table[t]*86400;//月份秒钟数相加if(Is_Leap_Year(syear)t1)seccount86400;//闰年2月份增加一天的秒钟数}seccount(uint32_t)(sday-1)*86400;//把前面日期的秒钟数相加seccount(uint32_t)hour*3600;//小时秒钟数seccount(uint32_t)min*60; //分钟秒钟数seccountsec;//最后的秒钟加上去//【寄存器操作】因为HAL库的不完善无法直接调用RTC_ReadTimeCounter函数。此处改用寄存器直接操作。RTC-CRL|14; //允许配置RTC-CNTLseccount0xffff;RTC-CNTHseccount16;RTC-CRL~(14);//配置更新while(!(RTC-CRL(15)));//等待RTC寄存器操作完成//【寄存器操作】结束return 0; //返回值:0,成功;其他:错误代码. }//读出时间 uint8_t RTC_Get(void){//读出当前时间值 //返回值:0,成功;其他:错误代码.static uint16_t daycnt0;uint32_t timecount0;uint32_t temp0;uint16_t temp10;//【寄存器操作】因为HAL库的不完善无法直接调用RTC_WriteTimeCounter函数。此处改用寄存器直接操作。timecountRTC-CNTH;//得到计数器中的值(秒钟数)timecount16;timecountRTC-CNTL;//【寄存器操作】结束temptimecount/86400; //得到天数(秒钟数对应的)if(daycnt!temp){//超过一天了daycnttemp;temp11970; //从1970年开始while(temp365){if(Is_Leap_Year(temp1)){//是闰年if(temp366)temp-366;//闰年的秒钟数else {temp1;break;}}else temp-365; //平年temp1;}ryeartemp1;//得到年份temp10;while(temp28){//超过了一个月if(Is_Leap_Year(ryear)temp11){//当年是不是闰年/2月份if(temp29)temp-29;//闰年的秒钟数else break;}else{if(tempmon_table[temp1])temp-mon_table[temp1];//平年else break;}temp1;}rmontemp11;//得到月份rdaytemp1; //得到日期}temptimecount%86400; //得到秒钟数rhourtemp/3600; //小时rmin(temp%3600)/60; //分钟rsec(temp%3600)%60; //秒钟rweekRTC_Get_Week(ryear,rmon,rday);//获取星期return 0; }uint8_t RTC_Get_Week(uint16_t year,uint8_t month,uint8_t day){ //按年月日计算星期(只允许1901-2099年)//已由RTC_Get调用uint16_t temp2;uint8_t yearH,yearL;yearHyear/100;yearLyear%100;// 如果为21世纪,年份数加100if (yearH19)yearL100;// 所过闰年数只算1900年之后的temp2yearLyearL/4;temp2temp2%7;temp2temp2daytable_week[month-1];if (yearL%40month3)temp2--;return(temp2%7); //返回星期值 }六温湿度传感器DHT11芯片驱动程序 设置 System Core——GPIO——点击PB2端口——设置为GPIO输出H O N H CHT11_DA dht11文件夹 dht11.h #ifndef DHT11_DHT11_H_ #define DHT11_DHT11_H_#include stm32f1xx_hal.h #include ../delay/delay.hvoid DHT11_IO_OUT (void); void DHT11_IO_IN (void); void DHT11_RST (void); uint8_t Dht11_Check(void); uint8_t Dht11_ReadBit(void); uint8_t Dht11_ReadByte(void); uint8_t DHT11_Init (void); uint8_t DHT11_ReadData(uint8_t *h);#endif /* DHT11_DHT11_H_ */ dht11.c #include dht11.h #include main.hvoid DHT11_IO_OUT (void){ //端口变为输出GPIO_InitTypeDef GPIO_InitStruct {0};GPIO_InitStruct.Pin DHT11_DA_Pin;GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull GPIO_NOPULL;GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOB, GPIO_InitStruct); }void DHT11_IO_IN (void){ //端口变为输入GPIO_InitTypeDef GPIO_InitStruct {0};GPIO_InitStruct.Pin DHT11_DA_Pin;GPIO_InitStruct.Mode GPIO_MODE_INPUT;GPIO_InitStruct.Pull GPIO_PULLUP;HAL_GPIO_Init(GPIOB, GPIO_InitStruct); }void DHT11_RST (void){ //DHT11端口复位发出起始信号IO发送DHT11_IO_OUT();HAL_GPIO_WritePin(GPIOB,DHT11_DA_Pin, GPIO_PIN_RESET);HAL_Delay(20); //拉低至少18msHAL_GPIO_WritePin(GPIOB,DHT11_DA_Pin, GPIO_PIN_SET);delay_us(30); //主机拉高20~40us }uint8_t Dht11_Check(void){ //等待DHT11回应返回1:未检测到DHT11返回0:成功IO接收uint8_t retry0;DHT11_IO_IN();//IO到输入状态while (HAL_GPIO_ReadPin(GPIOB,DHT11_DA_Pin)retry100){//DHT11会拉低40~80usretry;delay_us(1);}if(retry100)return 1; else retry0;while (!HAL_GPIO_ReadPin(GPIOB,DHT11_DA_Pin)retry100){//DHT11拉低后会再次拉高40~80usretry;delay_us(1);}if(retry100)return 1;return 0; }uint8_t Dht11_ReadBit(void){ //从DHT11读取一个位 返回值1/0uint8_t retry0;while(HAL_GPIO_ReadPin(GPIOB,DHT11_DA_Pin)retry100){//等待变为低电平retry;delay_us(1);}retry0;while(!HAL_GPIO_ReadPin(GPIOB,DHT11_DA_Pin)retry100){//等待变高电平retry;delay_us(1);}delay_us(40);//等待40us //用于判断高低电平即数据1或0if(HAL_GPIO_ReadPin(GPIOB,DHT11_DA_Pin))return 1; else return 0; }uint8_t Dht11_ReadByte(void){ //从DHT11读取一个字节 返回值读到的数据uint8_t i,dat;dat0;for (i0;i8;i){dat1;dat|Dht11_ReadBit();}return dat; }uint8_t DHT11_Init (void){ //DHT11初始化DHT11_RST();//DHT11端口复位发出起始信号return Dht11_Check(); //等待DHT11回应 }uint8_t DHT11_ReadData(uint8_t *h){ //读取一次数据//湿度值(十进制范围:20%~90%) 温度值(十进制范围:0~50°)返回值0,正常;1,失败uint8_t buf[5];uint8_t i;DHT11_RST();//DHT11端口复位发出起始信号if(Dht11_Check()0){ //等待DHT11回应for(i0;i5;i){//读取5位数据buf[i]Dht11_ReadByte(); //读出数据}if((buf[0]buf[1]buf[2]buf[3])buf[4]){ //数据校验*hbuf[0]; //将湿度值放入指针1h;*hbuf[2]; //将温度值放入指针2}}else return 1;return 0; } main.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.h #include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h #include ../../icode/relay/relay.h #include ../inc/retarget.h//用于printf函数串口重映射 #include ../../icode/usart/usart.h #include ../../icode/adc/adc.h #include ../../icode/rtc/rtc.h #include ../../icode/dht11/dht11.hint main(void) {uint8_t DHT11_BUF[2]{0};//用于存放DHT11数据MX_GPIO_Init();MX_DMA_Init();MX_ADC1_Init();MX_CAN_Init();MX_SPI2_Init();MX_USART1_UART_Init();MX_USART2_UART_Init();MX_USART3_UART_Init();MX_USB_PCD_Init();RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断HAL_Delay(500);//毫秒延时DHT11_Init();//传感器芯片初始化HAL_Delay(1500);//毫秒延时DHT11_ReadData(DHT11_BUF);//读出DHT11传感器数据参数是存放数据的数组指针while (1){DHT11_ReadData(DHT11_BUF);//读出DHT11传感器数据参数是存放数据的数组指针printf(湿度%02d 温度%02d℃\r\n,DHT11_BUF[0],DHT11_BUF[1]);//显示日期时间HAL_Delay(1500);//毫秒延时} } 七SPI总线闪存芯片驱动程序 设置 Connectivity——SPI2y——Mode选择全双工主机Full-Duplex Mastei——设置SPI端口模式(PB15 SPI2_MOSI、PB14 SPI2_MOSI、PB13 SPI2_SCK) ——设置参数Paramenter SettingMotorola 帧模式:摩托罗拉8Bits 数据大小:8位MSB First 首位:MSB起始2 分频器:218.0 MBits/s波特率:18.OMBHighHigh 高2 Edge CPHA:2边沿Disabled CRC校验:禁用Software 使能信号:软件——NVIC Setting——勾选中断SPI12 global interruptSystem Core——GPIO——选中PB12——设置PB12 W25Q128_cs为GPIO输出——H O P H W25Q128_csw25q128文件  w25qxx.h #ifndef W25Q128_W25QXX_H_ #define W25Q128_W25QXX_H_#include stm32f1xx_hal.h //HAL库文件声明 #include ../delay/delay.h//25系列FLASH芯片厂商与容量代号厂商代号EF #define W25Q80 0XEF13 #define W25Q16 0XEF14 #define W25Q32 0XEF15 #define W25Q64 0XEF16 #define W25Q128 0XEF17 #define W25Q256 0XEF18 #define EX_FLASH_ADD 0x000000 //W25Q128的地址是24位宽 extern uint16_t W25QXX_TYPE;//定义W25QXX芯片型号 extern SPI_HandleTypeDef hspi2; // //指令表 #define W25X_WriteEnable 0x06 #define W25X_WriteDisable 0x04 #define W25X_ReadStatusReg1 0x05 #define W25X_ReadStatusReg2 0x35 #define W25X_ReadStatusReg3 0x15 #define W25X_WriteStatusReg1 0x01 #define W25X_WriteStatusReg2 0x31 #define W25X_WriteStatusReg3 0x11 #define W25X_ReadData 0x03 #define W25X_FastReadData 0x0B #define W25X_FastReadDual 0x3B #define W25X_PageProgram 0x02 #define W25X_BlockErase 0xD8 #define W25X_SectorErase 0x20 #define W25X_ChipErase 0xC7 #define W25X_PowerDown 0xB9 #define W25X_ReleasePowerDown 0xAB #define W25X_DeviceID 0xAB #define W25X_ManufactDeviceID 0x90 #define W25X_JedecDeviceID 0x9F #define W25X_Enable4ByteAddr 0xB7 #define W25X_Exit4ByteAddr 0xE9 uint8_t SPI2_ReadWriteByte(uint8_t TxData);//SPI2总线底层读写 void W25QXX_CS(uint8_t a);//W25QXX片选引脚控制 uint8_t W25QXX_Init(void);//初始化W25QXX函数 uint16_t W25QXX_ReadID(void);//读取FLASH ID uint8_t W25QXX_ReadSR(uint8_t regno);//读取状态寄存器 void W25QXX_4ByteAddr_Enable(void);//使能4字节地址模式 void W25QXX_Write_SR(uint8_t regno,uint8_t sr);//写状态寄存器 void W25QXX_Write_Enable(void);//写使能 void W25QXX_Write_Disable(void);//写保护 void W25QXX_Write_NoCheck(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//无检验写SPI FLASH void W25QXX_Read(uint8_t* pBuffer,uint32_t ReadAddr,uint16_t NumByteToRead);//读取flash void W25QXX_Write(uint8_t* pBuffer,uint32_t WriteAddr,uint16_t NumByteToWrite);//写入flash void W25QXX_Erase_Chip(void);//整片擦除 void W25QXX_Erase_Sector(uint32_t Dst_Addr);//扇区擦除 void W25QXX_Wait_Busy(void);//等待空闲 void W25QXX_PowerDown(void);//进入掉电模式 void W25QXX_WAKEUP(void);//唤醒#endif /* W25Q128_W25QXX_H_ */w25qxx.c 里面定义了很多函数  #include w25qxx.h #include main.h uint16_t W25QXX_TYPEW25Q128;//默认是W25Q128//4Kbytes为一个Sector //16个扇区为1个Block //W25Q128 //容量为16M字节,共有128个Block,4096个Sector //SPI2总线读写一个字节 //参数是写入的字节返回值是读出的字节uint8_t SPI2_ReadWriteByte(uint8_t TxData) {uint8_t Rxdata;//定义一个变量RxdataHAL_SPI_TransmitReceive(hspi2,TxData,Rxdata,1,1000);//调用固件库函数收发数据return Rxdata;//返回收到的数据 }void W25QXX_CS(uint8_t a)//软件控制函数0为低电平其他值为高电平 {if(a0)HAL_GPIO_WritePin(W25Q128_CS_GPIO_Port, W25Q128_CS_Pin, GPIO_PIN_RESET);else HAL_GPIO_WritePin(W25Q128_CS_GPIO_Port, W25Q128_CS_Pin, GPIO_PIN_SET); } //初始化SPI FLASH的IO口 uint8_t W25QXX_Init(void) {uint8_t temp;//定义一个变量tempW25QXX_CS(1);//0片选开启1片选关闭W25QXX_TYPE W25QXX_ReadID();//读取FLASH ID.if(W25QXX_TYPE W25Q256)//SPI FLASH为W25Q256时才用设置为4字节地址模式{temp W25QXX_ReadSR(3);//读取状态寄存器3判断地址模式if((temp0x01)0)//如果不是4字节地址模式,则进入4字节地址模式{W25QXX_CS(0);//0片选开启1片选关闭SPI2_ReadWriteByte(W25X_Enable4ByteAddr);//发送进入4字节地址模式指令W25QXX_CS(1);//0片选开启1片选关闭}}if(W25QXX_TYPEW25Q256||W25QXX_TYPEW25Q128||W25QXX_TYPEW25Q64||W25QXX_TYPEW25Q32||W25QXX_TYPEW25Q16||W25QXX_TYPEW25Q80)return 0; else return 1;//如果读出ID是现有型号列表中的一个则识别芯片成功 } main.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.h #include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h #include ../../icode/relay/relay.h #include ../inc/retarget.h//用于printf函数串口重映射 #include ../../icode/usart/usart.h #include ../../icode/adc/adc.h #include ../../icode/rtc/rtc.h #include ../../icode/dht11/dht11.h #include ../../icode/w25q128/w25qxx.hint main(void) {uint8_t EX_FLASH_BUF[1];//W25Q128芯片数据缓存数组MX_GPIO_Init();MX_DMA_Init();MX_ADC1_Init();MX_CAN_Init();MX_SPI2_Init();MX_USART1_UART_Init();MX_USART2_UART_Init();MX_USART3_UART_Init();MX_USB_PCD_Init();RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断HAL_Delay(500);//毫秒延时W25QXX_Init();//W25QXX初始化printf(W25Q128测试程序按KEY1键显示芯片ID按KEY2键将0x00地址中的数值加1 \n\r);//显示程序说明文字while (1){if(KEY_1()){EX_FLASH_BUF[0]W25QXX_ReadID();//读取W25QXX芯片的ID码。W25Q128芯片十进制ID是61207十六进制表示是0xEF17printf(芯片ID%x \n\r,EX_FLASH_BUF[0]);//显示芯片IDBUZZER_SOLO1();//提示音}if(KEY_2()){BUZZER_SOLO1();//提示音W25QXX_Read(EX_FLASH_BUF,EX_FLASH_ADD,1);//读出W25QXX芯片数据参数读出数据存放的数组读取的开始地址数量EX_FLASH_BUF[0];//数据加1if(EX_FLASH_BUF[0]200)EX_FLASH_BUF[0]0;//如果数值大于指定最大值则清0W25QXX_Write(EX_FLASH_BUF,EX_FLASH_ADD,1);//写入W25QXX芯片数据参数读出数据存放的数组读取的开始地址数量printf(读出0x00地址数据%d \n\r,EX_FLASH_BUF[0]);//读出数据BUZZER_SOLO1();//提示音}}} 八USB从设备串口驱动程序 设置 时钟树视图——To USB使USB最终频率为48MHzConnectivity——USB——勾选Device设备——设置端口为USB接口PA12 USB_DPPA12 USB_DP——点击参数设置Parameter Setting——参数按默认设置——MVIC Setting——勾选USB低优先级USB low priority or CAN RX0 interruptsMiddleware——USB_DEVICE——选中串口Class For Fs IP Communication Device Class (Virtual Port Com)Disable禁用Audio Device Class音频设备类Communication Device Class (Virtual Port Com)通信设备类虚拟串口)Download Firmware Update Class (DFu)、下载固件更新类(DFU)Human lnterface Device Class (HID)人机界面设备类(HID)Custom Human Interface Device Class(HID)自定义人机界面设备类(HID)Mass Storage Class 大容量存储类Project Manager工程管理选项卡——Project——Linker SettingsMinimum Heap Size 0x1000Minimum Stack Size 0x1000...\USB_DEVICE\App usbd_cdc_if.h #define USB_REC_LEN 200//定义USB串口最大接收字节数 extern uint8_t USB_RX_BUF[USB_REC_LEN];//接收缓冲,最大USB_REC_LEN个字节.末字节为换行符 extern uint16_t USB_RX_STA;//接收状态标记接收到的有效字节数量void USB_printf(const char *format, ...);//USB模拟串口的打印函数 usbd_cdc_if.c uint8_t USB_RX_BUF[USB_REC_LEN];//接收缓冲,最大USB_REC_LEN个字节. uint16_t USB_RX_STA0;//接收状态标记接收到的有效字节数量static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) {/* USER CODE BEGIN 6 */if(*LenUSB_REC_LEN)//判断收到数据量是否小于寄存器上限{uint16_t i;USB_RX_STA *Len;//将数据量值放入标志位for(i0;i*Len;i)//循环循环次数数据数量USB_RX_BUF[i] Buf[i];//将数据内容放入数据寄存器}USBD_CDC_SetRxBuffer(hUsbDeviceFS, Buf[0]);USBD_CDC_ReceivePacket(hUsbDeviceFS);return (USBD_OK);/* USER CODE END 6 */ }uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len) {uint8_t result USBD_OK;/* USER CODE BEGIN 7 */uint32_t TimeStart HAL_GetTick();USBD_CDC_HandleTypeDef *hcdc (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;//if (hcdc-TxState ! 0) return USBD_BUSY;while(hcdc-TxState){if(HAL_GetTick()-TimeStart 10)return USBD_BUSY;elsebreak;}USBD_CDC_SetTxBuffer(hUsbDeviceFS, Buf, Len);result USBD_CDC_TransmitPacket(hUsbDeviceFS);TimeStart HAL_GetTick();while(hcdc-TxState){if(HAL_GetTick()-TimeStart 10)return USBD_BUSY;}/* USER CODE END 7 */return result; }#include stdarg.h void USB_printf(const char *format, ...)//USB模拟串口的打印函数 {va_list args;uint32_t length;va_start(args, format);length vsnprintf((char *)UserTxBufferFS, APP_TX_DATA_SIZE, (char *)format, args);va_end(args);CDC_Transmit_FS(UserTxBufferFS, length); } main.c #include ../../icode/led/led.h #include ../../icode/key/key.h #include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h #include ../../icode/relay/relay.h #include ../inc/retarget.h//用于printf函数串口重映射 #include ../../icode/usart/usart.h #include ../../icode/adc/adc.h #include ../../icode/rtc/rtc.h #include ../../icode/dht11/dht11.h #include ../../icode/w25q128/w25qxx.h #include ../../USB_DEVICE/App/usbd_cdc_if.hint main(void) {MX_GPIO_Init();MX_DMA_Init();MX_ADC1_Init();MX_CAN_Init();MX_SPI2_Init();MX_USART1_UART_Init();MX_USART2_UART_Init();MX_USART3_UART_Init();MX_USB_DEVICE_Init();RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断HAL_CAN_MspDeInit(hcan);//关闭CAN功能使USB功能可被电脑识别因USB与CAN共用一个RAM空间不能同时使用while (1){//USB模拟串口的查寻接收处理其编程原理与USART1串口收发相同if(USB_RX_STA!0)//判断是否有数据{USB_printf(USB_RX:);//向USB模拟串口发送字符串CDC_Transmit_FS(USB_RX_BUF,USB_RX_STA);//USB串口发送将接收的数据发回给电脑端参数1是数据内容参数2是数据量USB_printf(\r\n);//向USB模拟串口发送字符串回车USB_RX_STA0;//数据标志位清0memset(USB_RX_BUF,0,sizeof(USB_RX_BUF));//USB串口数据寄存器清0}}} 九省电模式、CRC与芯片ID 1.省电模式睡眠、停机、待机  1.1 睡眠模式测试程序 main.c while (1){LED_1(1);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭HAL_Delay(100);//在主循环里写入HAL库的毫秒级延时函数LED_1(0);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭HAL_Delay(100);//在主循环里写入HAL库的毫秒级延时函数//睡眠模式的启动函数HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON,PWR_SLEEPENTRY_WFI);//进入睡眠模式任意中断可唤醒}//参数1PWR_MAINREGULATOR_ON主电源开启 PWR_LOWPOWERREGULATOR_ON 低功耗电源开启 //参数2PWR_SLEEPENTRY_WFI中断唤醒 PWR_SLEEPENTRY_WFE 事件唤醒1.2 停机模式测试程序 设置一个外部中断唤醒的端口  PAO端口——设置为外部中断GPIO_EXT10 System Core——GPIO——右边点击GPIO栏——选中PA0 ——GPIO mode External lnterrupt Mode with Falling edge trigger detection下降沿触发——GPIO Pull-up/Pull-down Pull-up上拉——User Label KEY1——右边点击MVIC栏——勾选允许中断EXTl line0 interrupt main.c while (1){LED_1(1);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭HAL_Delay(100);//在主循环里写入HAL库的毫秒级延时函数LED_1(0);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭HAL_Delay(100);//在主循环里写入HAL库的毫秒级延时函数if(KEY_2()) //按键KEY2判断为1时按键按下{printf(进入【停机】状态按KEY1键外部中断唤醒 \n\r);//串口发送BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数//停机模式的启动函数HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);//进入【停机】模式//此处进入停机状态//接下来的程序在唤醒后执行SystemClock_Config();//唤醒后重新初始化时钟printf(退出【停机】状态 \n\r);//串口发送}} 1.3 待机模式测试程序 设置 待机模武是在停机模式的基础上美闭了SRAM的电源 使正在运行的程扇全部丢失只能复位重启由于在单片机正常运行PA0端口还需要被作为按键被使用只有讲入德机状态之前才需要设置为WKUP功能设置PAO——SYS_WKUP(此端口为专用待机唤醒端口)如何解决呢还是将PAO被定义为GPIO输入模式WKUP功能采用程序代码来设置System Core——SYS——System Wake-Up导致不能被勾选 main.c RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断printf(\n\r单片机启动按KEY2按键输入【待机】模式\n\r);//串口发送if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) ! RESET)//判断本次复位是不是从待机中唤醒{//可在此插入待机唤醒的处理程序printf(从【待机】模式中唤醒\n\r);//串口发送HAL_PWR_DisableWakeUpPin(PWR_WAKEUP_PIN1);//禁止WKUP引脚的唤醒功能__HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);//清除唤醒标志位}while (1){LED_1(1);//LED1灯控制1点亮0熄灭LED_2(0);//LED2灯控制1点亮0熄灭HAL_Delay(100);//在主循环里写入HAL库的毫秒级延时函数LED_1(0);//LED1灯控制1点亮0熄灭LED_2(1);//LED2灯控制1点亮0熄灭HAL_Delay(100);//在主循环里写入HAL库的毫秒级延时函数if(KEY_2()) //按键KEY2判断为1时按键按下{printf(进入【待机】状态按IoT开发板上的“休眠唤醒”键唤醒 \n\r);//串口发送BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数HAL_GPIO_WritePin(GPIOA,KEY1_Pin, GPIO_PIN_RESET);//PB0端口变低电平准备好唤醒键初始电平__HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);//清除 WKUP唤醒键 状态位HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);//使能WKUP引脚的唤醒功能使能PA0HAL_PWR_EnterSTANDBYMode();//进入【待机模式】}} 2.CRC数据校验方式与芯片ID测试程序 CRC本质是一个32位的带多项式计算的寄存器多用于数据通讯过程中的校验 设置 Computing——CRC——勾选激活Activated main.c #include main.h #include ../../icode/led/led.h #include ../../icode/key/key.h #include ../../icode/delay/delay.h #include ../../icode/buzzer/buzzer.h #include ../../icode/relay/relay.h #include ../inc/retarget.h//用于printf函数串口重映射 #include ../../icode/usart/usart.h #include ../../icode/adc/adc.h #include ../../icode/rtc/rtc.h #include ../../icode/dht11/dht11.h #include ../../icode/w25q128/w25qxx.hstatic const uint32_t CRCBUF[4] {0x61,0x62,0x63,0x64};int main(void) {uint32_t a,b,c;MX_GPIO_Init();MX_ADC1_Init();MX_CAN_Init();MX_SPI2_Init();MX_USART1_UART_Init();MX_USART2_UART_Init();MX_USART3_UART_Init();MX_CRC_Init();RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断printf(\n\rCRC计算测试程序\n\r);//串口发送while (1){//数据校验c HAL_CRC_Calculate(hcrc,(uint32_t *)CRCBUF,4);//载入CRC数据并返回计算结果参数2要计算的数组参数3数量开始前清除DR // c HAL_CRC_Accumulate(hcrc,(uint32_t *)CRCBUF,4);//载入CRC数据并返回计算结果参数2要计算的数组参数3数量保留了上一次的内容适用于不连续的累加式校验printf(CRC计算结果%08X \n\r,c);//将CRC计算结果显示在超级终端//读取芯片IDa *(__IO uint32_t *)(0X1FFFF7E8); //读出3个32位芯片ID高字节b *(__IO uint32_t *)(0X1FFFF7EC); //c *(__IO uint32_t *)(0X1FFFF7F0); //低字节printf(芯片ID: %08X %08X %08X \r\n,a,b,c); //从串口输出16进制IDwhile (1);//执行结束后在此循环}{ 十外部中断与定时器 1.外部中断外部中断的按键测试程序 设置 点击PA0——设置为外部中断GPIO_EX10System Core——GPIO——点击右侧GPIO选项卡——点击PA0一行——设置为 下降沿Extermal Interrupt Mode、上拉Pull-up、用户标注KEY1 ——点击右侧MVIC选项卡——勾选EXTIO中断允许——NVIC——点击NVIC选项卡——EXTI16: PVD中断、EXTI18:USB中断、EXTI17: RTC闹钟中断——点击Code generation选项卡——EXTl line0 interrupt设置生成代码 stm32f1xx_it.c void EXTI0_IRQHandler(void) //stm32f1xx_hal_gpio.c里面可以查看 {HAL_GPIO_EXTI_IRQHandler(KEY1_Pin); } main.c void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){//外部中断回调函数if(GPIO_Pin KEY1_Pin){//判断产生中断的端口if(KEY_1()){//再通过按键处理程序判断按键按下和放开LED_1_Contrary();//每按一次按键LED状态反转一次}} }while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */} key.c #include key.huint8_t KEY_1(void) {uint8_t a;a0;//如果未进入按键处理则返回0if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)GPIO_PIN_RESET){//读按键接口的电平 // HAL_Delay(20);//延时去抖动外部中断回调函数调用时不能使用系统自带的延时函数delay_us(20000);//延时去抖动if(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)GPIO_PIN_RESET){ //读按键接口的电平a1;//进入按键处理返回1}}while(HAL_GPIO_ReadPin(GPIOA,KEY1_Pin)GPIO_PIN_RESET); //等待按键松开delay_us(20000);//延时去抖动避开按键放开时的抖动return a; }uint8_t KEY_2(void) {uint8_t a;a0;//如果未进入按键处理则返回0if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)GPIO_PIN_RESET){//读按键接口的电平 // HAL_Delay(20);//延时去抖动外部中断回调函数调用时不能使用系统自带的延时函数delay_us(20000);//延时去抖动if(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)GPIO_PIN_RESET){ //读按键接口的电平a1;//进入按键处理返回1}}while(HAL_GPIO_ReadPin(GPIOA,KEY2_Pin)GPIO_PIN_RESET); //等待按键松开delay_us(20000);//延时去抖动避开按键放开时的抖动return a; } 2.定时器 Tout单位微秒 (ARR1) × (PCS1) / Tclk定时时间(uS)(计数周期1)×(分频系数1)÷输入时钟频率(MHz) 2.1 定时器中断的闪灯测试程序 设置 Timers——TIM2——Clock Source设置为内部时钟源Intemal Clock——点击参数设置Paramater SettingsPrescaler(PSC - 16 bits vallue) 9999分频系数Counter Mode up计数模式Counter Period (AutoReload Register 7199计数周期lnternall Clock Division (CKD) No Dinvision时钟分频因子auto-reload preload Enable自动重载初值NVIC Setting——勾选TIM2 global interrupt main.c void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){//定时器中断回调函数if(htim(htim2))//判断产生中断的定时器{LED_2_Contrary();//LED状态反转} }MX_TIM2_Init();HAL_TIM_Base_Start_IT(htim2);//开启定时器中断必须开启才能进入中断处理回调函数while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */} 2.2 定时器中断的PWM调光测试程序 设置 PB0——设置为TM3_CH3Timers——TIM3——勾选内部时钟Internal Clock——Channel3设置为PWM Generation CH3Parameter——Counter SettingsPrescaler (PSC - 16 bits value) 71 分频系数Counter Mode Up 计数模式Counter Period (AutoReload Register - 16 bits value ) 499 计数周期lnternal Clock Division (CKD) No Division 内部时钟因子auto-reload preload Enable 自动重装初值PWM Generation Channal3Mode PWM mode 1 PWN模式Pulse (16 bits value) 0 脉冲16位Output compare preload Enable 输出占空比 Fast Mode Disable 快速模式CH Polarity High 通道极性NMIC Setting——勾选TIM3 global interrupt允许中断GPIO Setting——选中PB0——Altemate Function Push Pull、High、LED1 main.c int main(void) {uint16_t a0;MX_CRC_Init();MX_TIM2_Init();MX_TIM3_Init();RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断HAL_TIM_Base_Start_IT(htim2);//开启定时器中断必须开启才能进入中断处理回调函数HAL_TIM_PWM_Start(htim3,TIM_CHANNEL_3);//开启定时器PWM输出while (1){__HAL_TIM_SetCompare(htim3,TIM_CHANNEL_3,a);//设置占空比函数参数3是PWM比值范围0~ARR计数周期a;//占空比值加1if(a499)a0;//当占空比值达到最大后清0HAL_Delay(10);//在主循环每10毫秒循环一次} } 十一RS485总线有线通讯驱动程序 设置 将PA2设置为——USAR_T2端口 将PA3设置为——SAR_RX端口Connecticity——USART2——Mode设置为异步模式Asynchronous——Parameter Settings参数设置Baud Rate 波特率 115200 Bits/sWord Length 位宽度 8 Bits (including Parity)Parity 校验 NoneStop Bits 停止位 1Data Direction 数据方向 Receive and TransmitOver Sampling 采样 16 Samples——NMIC Settings——勾选运行中断USART2 global interruptSystem Core——GPIO——点击右侧的GPIO选项卡——点击PA8这一行——L O N H RS485_RE rs485文件夹 rs485.h #ifndef RS485_RS485_H_ #define RS485_RS485_H_#include stm32f1xx_hal.h //HAL库文件声明 #include string.h//用于字符串处理的库 #include stdarg.h #include stdlib.h #include stdio.hextern UART_HandleTypeDef huart2;//声明USART2的HAL库结构体 void RS485_printf (char *fmt, ...); //RS485发送#endif /* RS485_RS485_H_ */ rs485.c #include rs485.h #include ../usart/usart.h #include main.h/* RS485总线通信使用UART8这是RS485专用的printf函数 调用方法RS485_printf(123); //向UART8发送字符123 */void RS485_printf (char *fmt, ...) {char buff[USART2_REC_LEN1]; //用于存放转换后的数据 [长度]uint16_t i0;va_list arg_ptr;HAL_GPIO_WritePin(RS485_RE_GPIO_Port,RS485_RE_Pin, GPIO_PIN_SET);//RS485收发选择线RE为高电平发送va_start(arg_ptr,fmt);vsnprintf(buff, USART2_REC_LEN1,fmt,arg_ptr);//数据转换istrlen(buff);//得出数据长度if(strlen(buff)USART2_REC_LEN)iUSART2_REC_LEN;//如果长度大于最大值则长度等于最大值多出部分忽略HAL_UART_Transmit(huart2,(uint8_t *)buff,i,0xffff);//串口发送函数串口号内容数量溢出时间va_end(arg_ptr);HAL_GPIO_WritePin(RS485_RE_GPIO_Port,RS485_RE_Pin, GPIO_PIN_RESET);//RS485收发选择线RE为低电平接收 } //所有USART串口的中断回调函数HAL_UART_RxCpltCallback统一存放在【USART1.C】文件中。 usart.c #include usart.huint8_t USART1_RX_BUF[USART1_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节. uint16_t USART1_RX_STA0;//接收状态标记//bit15接收完成标志bit14接收到0x0dbit13~0接收到的有效字节数目 uint8_t USART1_NewData;//当前串口中断接收的1个字节数据的缓存uint8_t USART2_RX_BUF[USART2_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节. uint16_t USART2_RX_STA0;//接收状态标记//bit15接收完成标志bit14接收到0x0dbit13~0接收到的有效字节数目 uint8_t USART2_NewData;//当前串口中断接收的1个字节数据的缓存 uint8_t RS485orBT;//当RS485orBT标志位为1时是RS485模式为0时是蓝牙模式uint8_t USART3_RX_BUF[USART3_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节. uint16_t USART3_RX_STA0;//接收状态标记//bit15接收完成标志bit14接收到0x0dbit13~0接收到的有效字节数目 uint8_t USART3_NewData;//当前串口中断接收的1个字节数据的缓存void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//串口中断回调函数 {if(huart huart1)//判断中断来源串口1USB转串口{printf(%c,USART1_NewData); //把收到的数据以 a符号变量 发送回电脑if((USART1_RX_STA0x8000)0){//接收未完成if(USART1_RX_STA0x4000){//接收到了0x0dif(USART1_NewData!0x0a)USART1_RX_STA0;//接收错误,重新开始else USART1_RX_STA|0x8000; //接收完成了}else{ //还没收到0X0Dif(USART1_NewData0x0d)USART1_RX_STA|0x4000;else{USART1_RX_BUF[USART1_RX_STA0X3FFF]USART1_NewData; //将收到的数据放入数组USART1_RX_STA; //数据长度计数加1if(USART1_RX_STA(USART1_REC_LEN-1))USART1_RX_STA0;//接收数据错误,重新开始接收}}}HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1); //再开启接收中断}if(huart huart2)//判断中断来源RS485{USART2_RX_BUF[0]USART2_NewData;//收到数据放入缓存数组只用到1个数据存放在数组[0]USART2_RX_STA;//数据接收标志位加1HAL_UART_Receive_IT(huart2,(uint8_t *)USART2_NewData, 1); //再开启接收中断}if(huart huart3)//判断中断来源串口3WIFI模块{printf(%c,USART3_NewData); //把收到的数据以 a符号变量 发送回电脑HAL_UART_Receive_IT(huart3,(uint8_t *)USART3_NewData,1); //再开启接收中断} } main.c #include ../../icode/rs485/rs485.hint main(void) { HAL_UART_Receive_IT(huart2,(uint8_t *)USART2_NewData,1); //开启串口2接收中断while (1){if(USART2_RX_STA!0)//串口2判断中断接收标志位【处理从RS485外部设备接收的字符】{BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数RS485_printf(%c,USART2_RX_BUF[0]); //串口发送USART2_RX_STA0;//清除标志位}if(KEY_1())//按下KEY1判断{BUZZER_SOLO2();//提示音RS485_printf(A);//向RS485发送字符A}if(KEY_2())//按下KEY2判断{BUZZER_SOLO2();//提示音RS485_printf(B);//向RS485发送字符B}}} 十二CAN总线有线通讯驱动程序 设置 配置时钟树视图——APB1设置为36(CAN功能由APB1提供时钟源)Connecttivity——CAN——勾选激活Activated——PB8和PB9设置为CAN接口——点击参数设置Parameter SettingBit Timings ParametersPrescaler (for Time Quantum) 9Time Quantum 250.0nsTime Quanta in Bit Segment 1 8 TimesTime Quanta in Bit Segment 2 7 TimesTime for one Bit 4000 nsBaud Rate 250000 bi/sReSynchronization Jump Width 1 TimeBasic ParametersTime Triggered Communication Mode DisableAutomatic Bus-Off Management DisableAutomatic Wake-Up Mode DisableAutomatic Retransmission DisableReceive Fifo Locked Mode DisableTransmit Fifo Priority DisableAdvanced ParametersOperating Mode Normal——MVIC Settings——勾选CAN RX1 can文件夹 can1.h #ifndef CAN_CAN1_H_ #define CAN_CAN1_H_#include stm32f1xx_hal.h //HAL库文件声明 #include string.h//用于字符串处理的库 #include stdarg.h #include stdlib.h #include stdio.hextern CAN_HandleTypeDef hcan;//声明的HAL库结构体CAN_TxHeaderTypeDef TxMeg;//CAN发送设置相关结构体 CAN_RxHeaderTypeDef RxMeg;//CAN接收设置相关结构体#define CAN1_ID_H 0x0000 //32位基础ID设置高16位 #define CAN1_ID_L 0x0000 //32位基础ID设置低16位 #define CAN1_MASK_H 0x0000 //32位屏蔽MASK设置高16位 #define CAN1_MASK_L 0x0000 //32位屏蔽MASK设置低16位 #define CAN1_REC_LEN 200//定义CAN1最大接收字节数extern uint8_t CAN1_RX_BUF[CAN1_REC_LEN];//接收缓冲,末字节为换行符 extern uint16_t CAN1_RX_STA;//接收状态标记void CAN_User_Init(CAN_HandleTypeDef* hcan );//CAN用户初始化函数 void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan);//CAN接收回调函数 uint8_t CAN1_SendNormalData(CAN_HandleTypeDef* hcan,uint16_t ID,uint8_t *pData,uint16_t Len);//CAN发送函数 void CAN1_printf (char *fmt, ...);//CAN总线通信使用CAN1这是CAN专用的printf函数#endif /* CAN_CAN1_H_ */ can1.c #include can1.h //库文件声明 #include main.hCAN_HandleTypeDef hcan;//声明的HAL库结构体uint8_t CAN1_RX_BUF[CAN1_REC_LEN];//接收缓冲,最大CAN1_REC_LEN个字节.末字节为换行符 uint16_t CAN1_RX_STA;//接收状态标记void CAN_User_Init(CAN_HandleTypeDef* hcan )//CAN总线用户初始化函数 {CAN_FilterTypeDef sFilterConfig;HAL_StatusTypeDef HAL_Status;TxMeg.IDE CAN_ID_STD;//扩展帧标识STD标准帧/EXT扩展帧TxMeg.RTR CAN_RTR_DATA;//远程帧标识DATA数据帧/REMOTE远程帧sFilterConfig.FilterBank 0;//过滤器0sFilterConfig.FilterMode CAN_FILTERMODE_IDMASK;//设为IDLIST列表模式/IDMASK屏蔽模式sFilterConfig.FilterScale CAN_FILTERSCALE_32BIT;//过滤器位宽度sFilterConfig.FilterIdHigh CAN1_ID_H;//32位基础ID设置高16位sFilterConfig.FilterIdLow CAN1_ID_L;//32位基础ID设置低16位sFilterConfig.FilterMaskIdHigh CAN1_MASK_H;//32位屏蔽MASK设置高16位sFilterConfig.FilterMaskIdLow CAN1_MASK_L;//32位屏蔽MASK设置低16位sFilterConfig.FilterFIFOAssignment CAN_RX_FIFO1;//接收到的报文放入FIFO1位置sFilterConfig.FilterActivation ENABLE;//ENABLE激活过滤器DISABLE禁止过滤器sFilterConfig.SlaveStartFilterBank 0;//过滤器组设置单个CAN总线时无用HAL_StatusHAL_CAN_ConfigFilter(hcan,sFilterConfig);//将以上结构体参数设置到CAN寄存器中if(HAL_Status!HAL_OK){//判断开启是否成功//开启CAN总线失败的处理程序写在此处printf(\n\rCAN设置失败\n\r); //串口发送}HAL_StatusHAL_CAN_Start(hcan); //开启CAN总线功能if(HAL_Status!HAL_OK){//判断开启是否成功//开启CAN总线失败的处理程序写在此处printf(\n\rCAN初始化失败\n\r); //串口发送}//若不使用CAN中断可删除以下4行HAL_StatusHAL_CAN_ActivateNotification(hcan,CAN_IT_RX_FIFO1_MSG_PENDING);//开启CAN总线中断if(HAL_Status!HAL_OK){//开启CAN总线挂起中断失败的处理程序写在此处printf(\n\rCAN中断初始化失败\n\r); //串口发送} } void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan) //接收回调函数函数名不可改 {uint8_t Data[8];//接收缓存数组HAL_StatusTypeDef HAL_RetVal;//判断状态的枚举HAL_RetValHAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO1,RxMeg,Data);//接收邮箱中的数据if (HAL_OKHAL_RetVal){//判断接收是否成功//接收成功后的数据处理程序写在此处。数据在Data数组中//以下2行是采用简单的寄存器查寻方式处理接收数据每次只接收1位。在实际项目中的复杂接收程序可自行编写。CAN1_RX_BUF[0]Data[0];//将接收到的数据放入缓存数组因只用到1个数据所以只存放在数据[0]位置CAN1_RX_STA;//数据接收标志位加1} } //CAN发送数据函数参数总线名ID数据数组数量。返回值0成功HAL_OK1参数错误HAL_ERROR2发送失败HAL_BUSY //示例CAN1_SendNormalData(hcan1,0,CAN_buffer,8);//CAN发送数据函数 uint8_t CAN1_SendNormalData(CAN_HandleTypeDef* hcan,uint16_t ID,uint8_t *pData,uint16_t Len) {HAL_StatusTypeDef HAL_RetVal;//判断状态的枚举uint16_t SendTimes,SendCNT0;uint8_t FreeTxNum0;uint32_t CAN_TX_BOX0;TxMeg.StdIdID;if(!hcan||!pData||!Len){printf(\n\rCAN发送失败\n\r); //串口发送return HAL_ERROR;//如果总线名、数据、数量任何一个为0则返回值为1}SendTimesLen/8(Len%8?1:0);FreeTxNumHAL_CAN_GetTxMailboxesFreeLevel(hcan);//得出空闲邮箱的数量TxMeg.DLC8;while(SendTimes--){//循环判断分批发送是否结束if(0SendTimes){//如果分批发送结束if(Len%8)TxMeg.DLCLen%8;//则加入最后不足8个的数据内容}while(0 FreeTxNum){FreeTxNum HAL_CAN_GetTxMailboxesFreeLevel(hcan);} // HAL_Delay(1);//延时防止速度过快导致的发送失败//开始发送数据参数总线名设置参数数据邮箱号HAL_RetValHAL_CAN_AddTxMessage(hcan,TxMeg,pDataSendCNT,CAN_TX_BOX0);if(HAL_RetVal!HAL_OK){printf(\n\rCAN总线忙碌\n\r); //串口发送return HAL_BUSY;//如果发送失败则返回值为2}SendCNT8;}return HAL_OK;//如果发送成功结束返回值为0 } //CAN总线通信使用CAN1这是CAN专用的printf函数 //调用方法CAN1_printf(123); //向UART8发送字符123 void CAN1_printf (char *fmt, ...) {char buff[CAN1_REC_LEN1]; //用于存放转换后的数据 [长度]uint16_t i0;va_list arg_ptr;va_start(arg_ptr, fmt);vsnprintf(buff, CAN1_REC_LEN1, fmt, arg_ptr);//数据转换istrlen(buff);//得出数据长度if(strlen(buff)CAN1_REC_LEN)iCAN1_REC_LEN;//如果长度大于最大值则长度等于最大值多出部分忽略CAN1_SendNormalData(hcan,0x12,(uint8_t *)buff,i);//CAN发送数据函数ID为0x12va_end(arg_ptr); }main.c #include ../../icode/can/can1.hint main(void) {RetargetInit(huart1);//将printf()函数映射到UART1串口上HAL_UART_Receive_IT(huart1,(uint8_t *)USART1_NewData,1);//开启串口1接收中断HAL_UART_Receive_IT(huart2,(uint8_t *)USART2_NewData,1); //开启串口2接收中断// HAL_CAN_MspDeInit(hcan);//关闭CAN功能使USB功能可被电脑识别因USB与CAN共用RAM空间不能同时使用HAL_CAN_MspInit(hcan);//开启CAN功能因USB与CAN共用RAM不能同时使用USB用完后想用CAN可在CAN收发前打开CAN_User_Init(hcan);//CAN1总线用户层初始化 同时开启CAN1功能while (1){if(CAN1_RX_STA!0)//CAN判断中断接收标志位【处理从CAN外部设备接收的字符】{BUZZER_SOLO1();//蜂鸣器输出单音的报警音样式1HAL库的精准延时函数CAN1_printf(%c,CAN1_RX_BUF[0]); //CAN总线发送CAN1_RX_STA0;//清除标志位}if(KEY_1())//按下KEY1判断{BUZZER_SOLO2();//提示音CAN1_printf(A);//向CAN1发送字符A}if(KEY_2())//按下KEY2判断{BUZZER_SOLO2();//提示音CAN1_printf(B);//向CAN1发送字符B}}}
http://www.dnsts.com.cn/news/46710.html

相关文章:

  • 学校网站开发4人小组分工付网站开发费用要计入什么科目
  • 个人网站的制作代码最好的企业网站源码
  • 开发网站用什么语言最好吗一建报考条件
  • 留学生做留服证明在哪个网站郴州市住房建设局门户网站
  • 建设网站有什么作用网站建设与维护是什么意思
  • 福建建设人才市场网站二级域名发放免费
  • h5网站模板wordpress 主题漏洞
  • 网站建设专题页面wordpress装修网插件
  • seo网站推广简历门户手机网站开发
  • 宁波网站建设详细方案模板wordpress首页太慢
  • 简单的英文网站模板推广软文范文
  • 北京哪家做网站和网络推广好的湖北正规网站建设质量保障
  • 精选聊城做网站的公司苏州品牌网站制作公司
  • 做视频的网站那几个盈利了色彩 导航网站
  • 金融审核网站制作广告策划方案怎么做
  • 邹城网站建设多少钱网址怎么申请
  • 网站在哪里建立肇庆市有那家做网站的
  • 如何建设自己的企业网站秦淮网站建设
  • 忽悠别人做商城网站自己做的网站如何发布
  • 上海化工网站建设选择网站模板注意事项
  • 网站开发语言 .net免费seo网站诊断
  • 宝安建设投资集团网站个人网页设计师
  • 做炭化料的网站常州金坛建设局网站
  • 做基金哪个网站好企业网站服务器多少钱
  • 做网站怎么套模板素材网站有哪些
  • 成都规划网站中国世界排名前300的大学
  • 网站开发技术职责广告联盟上怎么做网站
  • 设计网站都有什么作用是什么原因河源市做网站
  • 西安工程建设信息网站购物网站优化方案
  • 适合服务行业做推广的网站广告艺术设计学什么