stm32

基础外设

中断

SCB->VTOR = FLASH_BASE | 0x10000; 重定向中断向量表
__set_FAULTMASK(0);              打开关闭全局中断

唯一ID

static uint32_t idAddr[]={
  0x1FFFF7AC,/*STM32F0唯一ID起始地址*/
  0x1FFFF7E8,/*STM32F1唯一ID起始地址*/
  0x1FFF7A10, /*STM32F2唯一ID起始地址*/
  0x1FFFF7AC,/*STM32F3唯一ID起始地址*/
  0x1FFF7A10, /*STM32F4唯一ID起始地址*/
  0x1FF0F420,/*STM32F7唯一ID起始地址*/
  0x1FF80050, /*STM32L0唯一ID起始地址*/
  0x1FF80050, /*STM32L1唯一ID起始地址*/
  0x1FFF7590, /*STM32L4唯一ID起始地址*/
  0x1FF0F420
}; /*STM32H7唯一ID起始地址*/

Stm32CubeMx 和 HAL库

HAL库是上层封装库, 封装完善,但是性能稍微弱些,个人认为现在硬件资源比较多如果可以有稳定的开发环境和代码可以牺牲一些性能
LL库直接操作底层性能比较好,但是要对底层比较了解要做一些额外工作
CMSIS就是cortex M核心,包含系统时钟和启动代码,中断屏蔽等一些函数,基本不用我们操作这些东西
BSP就是对应每个开发板的板子驱动程序,如果你的硬件电路是参考开发板可以直接使用驱动程序
TCP,USB,FAT, RTOS,Graphic图形,这些是组件的方式提供,官方还能下载一些其他的组件例如:蓝牙,LORAWan

HAL使用基础

HAL库封装采用了回调的方式,官方封装上层,自己实现底层

例如:HAL_UART_Init   会回调  HAL_UART_MspInit 我们要实现这个函数具体引脚和中断等的配置,但是STM32cubemx帮我们配置好了,挺开心
每个外设数据传输方式都分为:阻塞, 中断,DMA传输,具体使用在每个头文件有介绍,固件库包目录有历程

输出传输完成和完成一半的时候会回调一些函数,例如:TxHalfCpltCallback(),用户要实现这个函数就可以在里面做一些任务,

回调函数原理,在每个函数头部用_weak声明,如果定义了新的函数编译器会链接新的函数不会发出警告

回调也可以用注册的方式,例如:HAL_UART_UnRegisterCallback()

Stm32CubeMx

看门狗配置

void HAL_WWDG_EarlyWakeupCallback(WWDG_HandleTypeDef *hwwdg)
{
	if(wwdg_tick++ < 1000) {
		HAL_WWDG_Refresh(hwwdg);
	}
}

ETH配置 LAN8720A

ADC配置

	//ADC初始化
	HAL_ADC_Start_DMA(&hadc3, (uint32_t*)&ADC_Value, 800);   //开启DMA

RTC低功耗

static void SystemPower_Config(void)
{
  /* Enable Power Control clock */
  __HAL_RCC_PWR_CLK_ENABLE();

  /* Enable Ultra low power mode */
  HAL_PWREx_EnableUltraLowPower();

  /* Enable the fast wake up from Ultra low power mode */
  HAL_PWREx_EnableFastWakeUp();
}
 


main中添加如下
----------------------------------------------------------------

 SystemPower_Config();

  /* Check and handle if the system was resumed from StandBy mode */ 
  if(__HAL_PWR_GET_FLAG(PWR_FLAG_SB) != RESET)
  {
    /* Clear Standby flag */
    __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB); 
		printf("OK");
  }
  
  /* Insert 5 seconds delay */
  HAL_Delay(5000);
	
	/* Disable all used wakeup sources*/
  HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
  
  /* Clear all related wakeup flags */
  __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
  
	//HAL_PWR_EnableFlashPowerDown();
	
	
	HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0xFFFF * 20, RTC_WAKEUPCLOCK_RTCCLK_DIV16);

  /* Enter the Standby mode */
  HAL_PWR_EnterSTANDBYMode();

DAC配置

HAL_DAC_SetValue(&hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, usRegHoldingBuf[index++] / 100.0 * 3.3 / 20  * (4095 / 3.3));

关闭DAC缓冲可以改变为线性输出

TIM配置PWM

HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1 );
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2 );
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3 );

TIM

I2C

HAL_I2C_Mem_Read(&hi2c1, 0xA1, i, I2C_MEMADD_SIZE_16BIT, point + i, 1, 1000);
HAL_I2C_Mem_Write(&hi2c1, 0xA0, i, I2C_MEMADD_SIZE_16BIT, point + i, 1, 1000);

SPI

Lwip

#define LWIP_DHCP 1  启用自动分配ip 注意(MAC地址要符合标准不然获取不到ip)
#define LWIP_DNS     启用DNS功能

LWIP_NETIF_LINK_CALLBACK  打开 网口热插拔回调处理

LWIP_DHCP_CHECK_LINK_UP   自动监测自动监测网络状态开启和关闭重新开启dhcp

在 MX_LWIP_Init()函数中修改
取消自动生成:dhcp_start(&gnetif);

添加
if (netif_is_link_up(&gnetif)) {
		dhcp_start(&gnetif);
}

添加 监测
void ethernetif_notify_conn_changed(struct netif *netif)
{
	if(netif_is_link_up(netif)) {
		netif_set_up(netif);
		if(SysConfigure.NetworkWay == 1) {  //动态ip
			struct dhcp *dhcp = netif_dhcp_data(netif);
			if(dhcp == NULL) {
				dhcp_start(netif);
			}
		}
	} else {
		netif_set_down(netif);
	}
}

DNS获取
err_t err = dns_gethostbyname("mqtt.huikezk.com", &dnsip, dns_found, NULL);
if(err == ERR_OK) {
	printf("DNS Found IP: %s\n", ip4addr_ntoa(&dnsip));
}
static void dns_found(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
{
  if (ipaddr != NULL)  {
    printf("DNS Found IP: %s\n", ip4addr_ntoa(ipaddr));
  }
}

状态回调打开自动生成监测函数:

在main主循环或者线程循环中 一直调用这个函数监测网络状态

void ethernetif_set_link(struct netif *netif)
{
  uint32_t regvalue = 0;
  /* Ethernet Link every 200ms */
  if (HAL_GetTick() - EthernetLinkTimer >= 200)
  {
    EthernetLinkTimer = HAL_GetTick(); 
    
    /* Read PHY_BSR*/
    HAL_ETH_ReadPHYRegister(&heth, PHY_BSR, &regvalue);
    
    regvalue &= PHY_LINKED_STATUS;
    
    /* Check whether the netif link down and the PHY link is up */
    if(!netif_is_link_up(netif) && (regvalue))
    {
      /* network cable is connected */ 
      netif_set_link_up(netif);        
    }
    else if(netif_is_link_up(netif) && (!regvalue))
    {
      /* network cable is disconnected */
      netif_set_link_down(netif);
    }
  }
}

UDP

 struct sockaddr_in my_addr;   //服务器网络地址结构体  
  struct sockaddr_in remote_addr; //客户端网络地址结构体  
  
  int server_sockfd;//服务器端套接字  
  
  memset((void *)&my_addr, 0, sizeof(my_addr)); //数据初始化--清零  
  memset((void *)&remote_addr, 0, sizeof(remote_addr));
  
  my_addr.sin_family = AF_INET; //设置为IP通信  
  my_addr.sin_addr.s_addr = INADDR_ANY;//服务器IP地址--允许连接到所有本地地址上  
  my_addr.sin_port = htons(502); //服务器端口号
  
  if((server_sockfd = socket(PF_INET,SOCK_STREAM,0)) < 0)  {     } 
  /*将套接字绑定到服务器的网络地址上*/  
  if (bind(server_sockfd,(struct sockaddr *)&my_addr, sizeof(struct sockaddr)) < 0)  {  }  
  
  struct timeval timeout={0, 10};
  //即timeout={4,0};或者timeout.tv_sec=4; timeout.tv_usec=0;
  //设置接收超时
  setsockopt(server_sockfd, SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(struct timeval));
  /* Infinite loop */
  for(;;)
  {
    socklen_t  len = 0;
    int reciverLen = 0;
    if((reciverLen = recvfrom(server_sockfd, udpBuf, BUFSIZ, 0, (struct sockaddr *)&remote_addr, &len)) > 0) {
      printf("%.*s", reciverLen, udpBuf);
    }
    
    osDelay(1);

static struct timeval timeout={0, 1000 * 1}; //1s
  //ÉèÖýÓÊÕ³¬Ê±
  if(setsockopt(server_sockfd, SOL_SOCKET, SO_RCVTIMEO,(char*)&timeout,sizeof(struct timeval)) < 0) {
    Soft_Reset();
  }
  if(setsockopt(server_sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {//ÉèÖÃÌ×½Ó×Ö·¢Ë͹㲥
    Soft_Reset();
  }

TCP keepalive

1.设置 LWIP_KEEPALIVE true


if(setsockopt(server_sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepalive, sizeof(keepalive)) < 0)
    /*将套接字绑定到服务器的网络地址上*/  
    if (bind(server_sockfd,(struct sockaddr *)&my_addr, sizeof(struct sockaddr)) < 0)  {  }  
    /*监听连接请求--监听队列长度为1*/  
    if(listen(server_sockfd, 1) < 0) { }
    u32_t sin_size = sizeof(struct sockaddr_in);  
    
  /* Infinite loop */
  for(;;)
  {
		/*等待客户端连接请求到达*/ 
		if((client_sockfd = accept(server_sockfd,(struct sockaddr *)&remote_addr, &sin_size)) < 0) {  
        printf("accept faild");  
				continue;
    }
		setsockopt(client_sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (void*)&keepidle , sizeof(keepidle));
		setsockopt(client_sockfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepinterval , sizeof(keepinterval));
		setsockopt(client_sockfd, IPPROTO_TCP, TCP_KEEPCNT, (void *)&keepcount , sizeof(keepcount));
		setsockopt(client_sockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&flag , sizeof(flag)); //没缓冲直接发送
		
		printf("accept client %s:%d/n", inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port));
		
		/*接收客户端的数据并将其发送给客户端--recv返回接收到的字节数,send返回发送的字节数*/  
    while((len = recv(client_sockfd, buf, BUFSIZ, 0)) > 0)  
    {  
        buf[len]='\0';  
        printf("%s/n",buf);  
        if(send(client_sockfd,buf,len,0) < 0)    {  
            break;
        }  
    } 
		close(client_sockfd);
		printf("sock disconnect\n");
  }

LWIP listen(server_sockfd, 1) 监听个数

TCP_LISTEN_BACKLG 设置为 true

Lwip连接个数被限制

发现MEMP_NUM_NETCONN这个值太小了  导致后面的连接分配不到内存      将其改大些就可以了

LwIP BUG之TCP连接丢失
LwIP所有版本包括最新的2.0版本具有以下缺陷,当用户使用raw编程并在err或poll回调函数中操作了内核全局tcp_active_pcbs链表(最典型的,比如进行了重连操作),将有可能导致链表异常,严重情况下,链表中的很多tcp_pcb会丢失,从而导致部分连接没有任何反应,出现假死的现象。

网络质量不好或者其他原因具体原因未知,因为同样的程序我就一个项目发现了问题

解决方法

跟踪发现是这个结构体用完了没有释放导致,添加定时监测,如果不能再申请到说明用完了重启系统
//检测内存
struct tcp_seg *seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG);
if(seg == NULL)
	Soft_Reset();
memp_free(MEMP_TCP_SEG, seg);			

stm32 lua

Lua的官网是:www.lua.org

移植



加入�lua源代码到MDK,把lua.c 和luac.c删除。

l  改动堆栈大小:堆最小为5.5kb,栈最小是1.5kb。lua的空间分配在堆空间。16kb的内存建议分配是堆11Kb,栈4Kb,留1Kb给全局变量。

在startup_stm32f10x_md.s文件里

; stack size 0x1 == 4Kb

Stack_Size     EQU     0x01

; heap size 0x2c00 == 11Kb

Heap_Size       EQU     0x02C00



1) 把 lua.c 和 luac.c 删除,这两个是一个Lua Shell,和平台相关,单片机中一般没用。

2) 对内存敏感的项目可以替换掉 lauxlib.c 文件里 l_alloc 函数调用的 free 和 realloc 函数。

3) loslib.c 和系统相关,单片机中最多跑RTOS,所以这个文件可以删除。

4) liolib.c 中使用了标准文件操作fopen、fclose、fread、fwrite等函数。虽然有些单片机支持这些函数,但还是要自己重定向这些函数,而且在单片机中一般也不用文件来操作IO,所以这个文件可以删除。

5) 如果删除了 loslib.c 和 liolib.c,那么在 linit.c 中要把 loadlibs 数组中相关的元素注释掉。这样调用 luaL_openlibs 时就不会加载这两个库了。

6) 在luaconfig.h 中有 luai_writestring 和 luai_writeline 两个宏,这两个宏关系到了 lua 中 print 的输出,需要针对平台重定向,一般定向到调试串口就行。还有个 luai_writestringerrir 宏,定义了 lua 如何报错,可以定义到调试串口,也可以定义到log文件,或者两者兼有。

7)LUA_32BITS使能  int 和 float使用32否则使用64位

8)添加time()函数

完成以上6步,lua就移植完成了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值