⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 client.c

📁 LWIP在STM32裸机上的移植
💻 C
字号:
#include "client.h"

const u8 UDP_Data[] = "This is the lwIP example about UDP client.\r\n";

/*ADC为12位模数转换器,只有ADCConvertedValue的低12位有效*/ 
__IO uint32_t ADCConvertedValue;

u16 ADCConvertedValueLocal1,ADCConvertedValueLocal2;

u16 Voltage[2]={0};		//保存ADC转换的电压值(4位整数值)

u8 Data[8]={0};			//保存转换后的ASCII字符
u8 Data1[8]={0}; 		//发送的数据(ADC1转换值)
u8 Data2[8]={0};		//发送的数据(ADC2转换值)

u8 zifu[] = "V\r\n";
u8 divstr[] = "----------\r\n";


struct ip_addr destAddr;	//远程主机IP地址

/******************************************************************************
** Function name:      mux_n
** Descriptions:       计算10的n次幂,n要大于等于0
** input parameters:    n : 10的n次幂
** output parameters:  sum: 返回运算后的结果
** Returned value:     无   
******************************************************************************/
u32 mux_n (u8  n)
{
    u8  i;
    u32 sum = 10;
    for (i = 1; i < n; i++) 
        sum = sum * 10;

    if (n == 0) sum = 1;

    return sum;
}

/******************************************************************************
** Function name:      Data_ASICC
** Descriptions:       将一个最大值四位的整数转换为字符串
** input parameters:   charge_data: 要转换的3位整数
** output parameters:  无
** Returned value:     无   
******************************************************************************/
void Data_ASICC (u16 charge_data)
{
    u8  i,index = 0;
    u16 ulchar, temp;
    for (i = 0; i < 4; i++) 
	{
        ulchar = charge_data / (mux_n(3 - i)) % 10 + '0';   //取出最高位
        Data[index++] = ulchar;
        if (i == 0)                                                  				   
        	Data[index++]='.'; 								//小数点                            

        ulchar  = (ulchar - '0');                         	//下面四条语句是将最高位消除,为下次再取一个最高位做准备
              
        temp    = (mux_n(3 - i));
        ulchar  = ulchar * temp;
        
		charge_data = charge_data - ulchar;
    }
	Data[index++] = 'V';
	Data[index++] = '\r';
	Data[index] = '\n';
}

/******************************************************************************
** Function name:      HexToASCII
** Descriptions:       将二进制数转换成ASCII字符
** input parameters:   data: 要转换的整数
** output parameters:  无
** Returned value:     无   
******************************************************************************/
void HexToASCII(u16 data)
{
	Data[0] = data/1000%10 + 0x30;
	Data[1] = '.';
	Data[2] = data/100%10 + 0x30;
	Data[3] = data/10%10 + 0x30; 
	Data[4] = data%10 + 0x30;
	Data[5] = 'V';
	Data[6] = '\r';
	Data[7] = '\n';	  
}

//复制字符数组的内容
void data_cpy(u8 *dest, u8 *src)
{
  u8 i = 0;
  for(i = 0;i < 8;i++)
  {
    dest[i] = src[i];          
  }
}

void Get_ADC_Data(void)
{
	ADCConvertedValueLocal1 = (ADCConvertedValue&0x00000fff);
	Voltage[0] = (ADCConvertedValueLocal1*3300/4096);   		//PC0电压值	//将电压值*1000,保存成整数   

	ADCConvertedValueLocal2 = ((ADCConvertedValue>>16)&0x00000fff);
	Voltage[1] = (ADCConvertedValueLocal2*3300/4096);   		//PC1电压值	//0x1000	
   
	Delay(200000);               //原来的延时参数为8000000
}

//注意,ADC采样后的VOLTAGE已经是一个四位数,可以直接转换为ASIIC码输出
void Turn_ADC_Data(void)
{
	HexToASCII(Voltage[0]);
//	Data_ASICC(Voltage[0]);		//PC0电压值  
    data_cpy(Data1,Data);

	HexToASCII(Voltage[1]);                		
//	Data_ASICC(Voltage[1]);		//PC1电压值    
	data_cpy(Data2,Data);
	    
	Delay(500000);
}

void ADC_Configuration(void)
{  	
	ADC_InitTypeDef ADC_InitStructure;
	DMA_InitTypeDef DMA_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	/* 使能DMA时钟*/
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

	/* 使能ADC1、ADC2和GPIOC端口*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2 | RCC_APB2Periph_GPIOC, ENABLE);
	
	/* 配置PC0作为ADC的模拟量输入,作为ADC通道1的模拟通道10 */  
  	GPIO_InitStructure.GPIO_Pin =GPIO_Pin_0 | GPIO_Pin_3;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  	GPIO_Init(GPIOC, &GPIO_InitStructure);
  
	/* DMA1通道1参数配置*/
	DMA_DeInit(DMA1_Channel1);/*失能DMA1通道1*/
  
	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;			/*指定DMA的外设地址为ADC1的数据寄存器地址*/
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue;/*指定DMA的内存基地址*/
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;					/*外设作为数据传输来源*/
	DMA_InitStructure.DMA_BufferSize = 2;								/*2个数据单位,即32位*/
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	/*外设地址寄存器不变*/
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;			/*内存地址寄存器不变*/
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;	/*数据宽度为字,16位*/
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;		/*设定外设数据宽度*/
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;						/*工作在循环缓存模式*/
	DMA_InitStructure.DMA_Priority = DMA_Priority_High;					/*DMAx通道拥有高优先级*/
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;						/*DMAx通道没有设置为内存到内存传输*/
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
  
	/*使能DMA1通道1*/
	DMA_Cmd(DMA1_Channel1, ENABLE);
  
	/*ADC1配置*/
	ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;					/*ADC工作在同步规则模式*/
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;						/*扫描模式*/
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;					/*连续模式*/
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	/*软件启动*/
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;				/*数据右对齐*/
	ADC_InitStructure.ADC_NbrOfChannel = 1;								/*一个ADC通道进行规则转换*/
	ADC_Init(ADC1, &ADC_InitStructure);
	ADC_Init(ADC2, &ADC_InitStructure);

	/* 设置ADC1的采样顺序和转换时间*/ 
	ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5);	//PC0

	/*使能ADC1的DMA请求*/
	ADC_DMACmd(ADC1, ENABLE);

	/*使能ADC1*/
	ADC_Cmd(ADC1, ENABLE);

	/*使能ADC1重置校准寄存器*/   
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));

	/*开始指定ADC1的校准状态*/
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));     

	/* ADC1软转换开始*/ 
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  
	/*ADC2的配置*/
	ADC_RegularChannelConfig(ADC2, ADC_Channel_13, 1, ADC_SampleTime_71Cycles5);	//PC3
	
	ADC_DMACmd(ADC2, ENABLE);
	ADC_Cmd(ADC2, ENABLE);
	
	ADC_ResetCalibration(ADC2);
	while(ADC_GetResetCalibrationStatus(ADC2));
	
	ADC_StartCalibration(ADC2);
	while(ADC_GetCalibrationStatus(ADC2));
	
	/* ADC2软转换开始*/
	ADC_SoftwareStartConvCmd(ADC2, ENABLE);
}

/**
  * @brief  Initialize the UDP client and then UDP server application.
  * @param  None
  * @retval None
  */
void client_init(void)
{
	struct udp_pcb *upcb;
	struct pbuf *p;

//	p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM);
	p = pbuf_alloc(PBUF_TRANSPORT, sizeof(UDP_Data), PBUF_RAM);
	p->payload = (void *)UDP_Data;
                                  
	/* Create a new UDP control block  */
	upcb = udp_new(); 

	/* Bind the upcb to the UDP_PORT port */
	/* Using IP_ADDR_ANY allow the upcb to be used by any local interface */	
	udp_bind(upcb,IP_ADDR_ANY,UDP_CLIENT_PORT);  //STM32_UDP客户端的端口:121
   
	/* Connect the upcb  */
	udp_connect(upcb, IP_ADDR_BROADCAST, UDP_SERVER_PORT); //IP_ADDR_BROADCAST : 0xffffffffUL (上位机UDP服务器端口:120)	

	/* Send out an UDP datagram to inform the server that we have strated a client application */
	udp_send(upcb, p); 
	udp_send(upcb, p);
	udp_send(upcb, p);			//连续发送三次  

	/* Reset the upcb */
	udp_disconnect(upcb);
   
	/* Bind the upcb to any IP address and the UDP_PORT port*/
	/* Using IP_ADDR_ANY allow the upcb to be used by any local interface */
	udp_bind(upcb, IP_ADDR_ANY, UDP_SERVER_PORT);  //原来是UDP_CLIENT_PORT (STM32_UDP服务器的端口:120)
   
	/* Set a receive callback for the upcb */
	udp_recv(upcb, udp_server_callback, NULL);

	/* Free the p buffer */
	pbuf_free(p); 
}

/**
  * @brief This function is called when an UDP datagrm has been received on the port UDP_PORT.
  * @param arg : user supplied argument (udp_pcb.recv_arg)
  * @param upcb: the udp_pcb which received data
  * @param p   : the packet buffer that was received
  * @param addr: the remote IP address from which the packet was received
  * @param port: the remote port from which the packet was received
  * @retval None
  */
void udp_server_callback(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
{
	__IO uint8_t iptab[4];
	uint8_t iptxt[20];

	destAddr = *addr;	//获得远程主机的IP地址(STM32的TCP客户端和远程主机连接时需要)
    
	/* Read the Client's IP address */
	iptab[0] = (uint8_t)((uint32_t)(addr->addr) >> 24);  
	iptab[1] = (uint8_t)((uint32_t)(addr->addr) >> 16);
	iptab[2] = (uint8_t)((uint32_t)(addr->addr) >> 8);
	iptab[3] = (uint8_t)((uint32_t)(addr->addr));

	sprintf((char*)iptxt, "%d.%d.%d.%d", iptab[3], iptab[2], iptab[1], iptab[0]);

  	/* Display the client's IP address */
  	/* If there is more than one client connected, the IP address of the last one connected will be displayed */
	printf("The client port : %d\n",port);    
	printf("The client IP address : %s\n",iptxt);

  	/* Connect to the remote client */
  	udp_connect(upcb, addr, port);
    
  	/* Tell the client that we have accepted it */
  	udp_send(upcb, p);

//	udp_sendto(upcb,p,addr,port);		//用此函数,UDP客户端为什么收不到数据呢?!

	GPIOD->ODR ^= GPIO_Pin_4;			//LED3闪烁(表示STM32的UDP客户端接收到数据)

  	/* free the UDP connection, so we can accept new clients */
  	udp_disconnect(upcb);

	/* Free the p buffer */
	pbuf_free(p);
}

void TCP_Client_Init(void)
{
	struct tcp_pcb *pcb;
//	struct ip_addr destAddr;
  
//	IP4_ADDR(&destAddr,192,168,4,123);		//1.指定远程主机IP地址;  2.通过接收UDP客户端数据包,获取远程主机IP地址

	/* Create a new TCP control block  */
	pcb = tcp_new();

	/* Assign to the new pcb a local IP address and a port number */
	tcp_bind(pcb, IP_ADDR_ANY, TCP_PORT);

	/* Connect to the server: send the SYN */
	tcp_connect(pcb, &destAddr, TCP_PORT, tcp_client_connected);
}

/*与远程服务器建立连接时调用*/
err_t tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
	tcp_write(tpcb,Data1,sizeof(Data1),0);
//	tcp_write(tpcb,zifu,sizeof(zifu),0);

	tcp_write(tpcb,Data2,sizeof(Data2),0);
//	tcp_write(tpcb,zifu,sizeof(zifu),0); 

	tcp_write(tpcb,divstr,sizeof(divstr),0);
	  
	tcp_close(tpcb);
   
	return ERR_OK;
}
//疑问:在STM32上建立TCP客户端,向远程主机(TCP服务器)发送连接请求。当连接正确时,
//      调用此回调函数发送数据,发送完毕关闭连接。
//		一次调用回调函数为什么无法发送多个字符串?即遇到字符串结束符号'\0',便终
//		止了后续tcp_write() 函数发送的内容。
//解决:sizeof(Data)求字符串的长度,包括了字符串结束符\0';
//		strlen(Data)求字符串的长度,指字符串的实际长度。
//程序中用 tcp_write(tpcb,Data,strlen(Data),0);	便解决此问题。

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -