Any difference between ~ and $HOME?
It's true to a certain extent.


$HOME is an expression for expansion of the environment variable HOME
~ (tilde) is a separate shell expansion component
see footnote


When used as a command argument and in separation from other strings, $HOME and ~ are usually equivalent.

But there are cases where they differ:


if the string containing either is quoted, for example:

# echo "My home directory is $HOME"
My home directory is /Users/techraf
# echo "My home directory is ~"
My home directory is ~

if they are concatenated to a string, for example:


dd if=${HOME}/source_file of=${HOME}/destination_file will work.

Shell will pass arguments if=/Users/techraf/source_file and of=/Users/techraf/destination_file containing a valid path to the dd command.
dd if=~/source_file of=~/destination_file won't work

Shell will pass arguments if=~/source_file and of=~/destination_file to the dd command and it will report an error as it does not interpret ~.





footnote:

In fact ~ is by default replaced with the value of HOME, but if HOME is empty, it is resolved to a home directory:

# echo $HOME
/Users/techraf
# export HOME=/dummy
# echo $HOME
/dummy
# echo ~
/dummy




# unset HOME
# echo $HOME

# echo ~
/Users/techraf


From man bash:


  Tilde Expansion
  
  If a word begins with an unquoted tilde character (`~'), all of the characters preceding the first unquoted slash (or all  characters,  if  there  is  no unquoted  slash)  are  considered a tilde-prefix.  If none of the characters in the tilde-prefix are quoted, the characters in the tilde-prefix following the tilde are treated as a possible login name.  If this login name is the null string, the tilde is replaced with the value of the shell parameter HOME.
  
  If  HOME  is  unset,  the  home  directory of the user executing the shell is substituted instead.  Otherwise, the tilde-prefix is replaced with the home directory associated with the specified login name.